Was ist die Aufregung um Haskell? [geschlossen]


109

Ich kenne ein paar Programmierer, die immer wieder über Haskell sprechen, wenn sie untereinander sind, und hier auf SO scheint jeder diese Sprache zu lieben. In Haskell gut zu sein, scheint ein Markenzeichen eines genialen Programmierers zu sein.

Kann jemand ein paar Haskell-Beispiele nennen, die zeigen, warum es so elegant / überlegen ist?

Antworten:


134

Die Art und Weise, wie es mir gezeigt wurde, und was ich denke, nachdem ich einen Monat lang an Haskell gelernt habe, ist die Tatsache, dass funktionale Programmierung Ihr Gehirn auf interessante Weise verdreht: Es zwingt Sie, über vertraute Probleme auf unterschiedliche Weise nachzudenken : Denken Sie anstelle von Schleifen an Karten, Falten und Filter usw. Wenn Sie mehr als eine Perspektive auf ein Problem haben, können Sie im Allgemeinen besser über dieses Problem nachdenken und bei Bedarf die Ansicht wechseln.

Das andere wirklich nette an Haskell ist das Typensystem. Es ist streng typisiert, aber die Typinferenz-Engine lässt es sich wie ein Python-Programm anfühlen, das Ihnen auf magische Weise sagt, wenn Sie einen dummen typbezogenen Fehler gemacht haben. Haskells Fehlermeldungen in dieser Hinsicht fehlen etwas, aber wenn Sie sich mit der Sprache vertraut machen, werden Sie sich sagen: So soll das Tippen sein!


47
Es sollte beachtet werden, dass Haskells Fehlermeldungen nicht fehlen, Ghcs. Der Haskell-Standard legt nicht fest, wie Fehlermeldungen ausgegeben werden.
PyRulez

Für die Plebs wie mich steht GHC für Glasgow Haskell Compiler. en.wikipedia.org/wiki/Glasgow_Haskell_Compiler
Lorem Ipsum

137

Dies ist das Beispiel, das mich überzeugt hat, Haskell zu lernen (und Junge, bin ich froh, dass ich es getan habe).

-- program to copy a file --
import System.Environment

main = do
         --read command-line arguments
         [file1, file2] <- getArgs

         --copy file contents
         str <- readFile file1
         writeFile file2 str

OK, es ist ein kurzes, lesbares Programm. In diesem Sinne ist es besser als ein C-Programm. Aber wie unterscheidet sich das von einem Python-Programm mit einer sehr ähnlichen Struktur?

Die Antwort ist faule Bewertung. In den meisten Sprachen (auch in einigen funktionalen) würde ein Programm wie das oben beschriebene dazu führen, dass die gesamte Datei in den Speicher geladen und dann unter einem neuen Namen erneut ausgeschrieben wird.

Haskell ist "faul". Es berechnet keine Dinge, bis es benötigt wird, und im weiteren Sinne berechnet es keine Dinge, die es nie benötigt. Wenn Sie beispielsweise die writeFileZeile entfernen würden, würde Haskell sich überhaupt nicht darum kümmern, etwas aus der Datei zu lesen.

So wie es ist, erkennt Haskell, dass das writeFilevon dem abhängt readFile, und kann so diesen Datenpfad optimieren.

Während die Ergebnisse vom Compiler abhängig sind, passiert normalerweise Folgendes, wenn Sie das obige Programm ausführen: Das Programm liest einen Block (z. B. 8 KB) der ersten Datei, schreibt ihn dann in die zweite Datei und liest dann einen weiteren Block aus der ersten Datei und schreibt es in die zweite Datei und so weiter. (Versuchen Sie es zu laufen strace!)

... was sehr ähnlich aussieht wie die effiziente C-Implementierung einer Dateikopie.

Mit Haskell können Sie also kompakte, lesbare Programme schreiben - oft ohne viel Leistung zu verlieren.

Eine andere Sache, die ich hinzufügen muss, ist, dass Haskell es einfach schwierig macht, fehlerhafte Programme zu schreiben. Das erstaunliche Typsystem, das Fehlen von Nebenwirkungen und natürlich die Kompaktheit des Haskell-Codes reduzieren Fehler aus mindestens drei Gründen:

  1. Besseres Programmdesign. Reduzierte Komplexität führt zu weniger Logikfehlern.

  2. Kompakter Code. Es gibt weniger Zeilen, in denen Fehler vorhanden sind.

  3. Fehler kompilieren. Viele Fehler sind einfach nicht gültig, Haskell .

Haskell ist nicht jedermanns Sache. Aber jeder sollte es versuchen.


Wie genau würden Sie die 8-KB-Konstante ändern (oder was auch immer)? Weil ich wetten würde, dass eine Haskell-Implementierung ansonsten langsamer wäre als eine C-Version, insbesondere ohne
Vorabruf

1
@Mehrdad Sie können die Puffergröße mit ändern hSetBuffering handle (BlockBuffering (Just bufferSize)).
David

3
Es ist erstaunlich, dass diese Antwort 116 positive Stimmen hat, aber was da drin ist, ist einfach falsch. Dieses Programm wird die gesamte Datei lesen, es sei denn , Sie faul Bytestrings verwenden (die Sie mit tun Data.Bytestring.Lazy.readFile), die nichts zu tun haben mit Haskell eine faule (nicht streng) Sprache. Monaden sequenzieren - dies bedeutet ungefähr "alle Nebenwirkungen sind erledigt, wenn Sie das Ergebnis herausnehmen". Was die "Lazy Bytestring" -Magie betrifft: Dies ist gefährlich, und Sie können dies mit einer ähnlichen oder einfacheren Syntax in den meisten anderen Sprachen tun.
Jo So

14
Der langweilige alte Standard readFilemacht auch faul IO auf die gleiche Weise Data.ByteString.Lazy.readFile. Die Antwort ist also nicht falsch und es handelt sich nicht nur um eine Compileroptimierung. Dies ist in der Tat Teil der Spezifikation für Haskell : "Die readFileFunktion liest eine Datei und gibt den Inhalt der Datei als Zeichenfolge zurück. Die Datei wird bei Bedarf wie bei träge gelesen getContents."
Daniel Wagner

1
Ich denke, die anderen Antworten weisen auf Dinge hin, die an Haskell etwas Besonderes sind. Viele Sprachen / Umgebungen haben Streams. In Node können Sie etwas Ähnliches tun : const fs = require('fs'); const [file1, file2] = process.argv.slice(2); fs.createReadStream(file1).pipe(fs.createWriteStream(file2)). Bash hat auch etwas ähnliches:cat $1 > $2
Max Heiber

64

Sie stellen die falsche Frage.

Haskell ist keine Sprache , wo man Blick auf ein paar coolen Beispiele geht und gehen „Aha, ich sehe jetzt, das ist , was es gut ist!“

Es ist eher so, als hätten wir all diese anderen Programmiersprachen und sie sind alle mehr oder weniger ähnlich, und dann gibt es Haskell, das völlig anders und verrückt ist, auf eine Weise, die total fantastisch ist, wenn man sich erst einmal an die Verrücktheit gewöhnt hat. Das Problem ist jedoch, dass es eine Weile dauert, bis man sich an die Verrücktheit gewöhnt hat. Dinge, die Haskell von fast jeder anderen Sprache unterscheiden:

  • Faule Bewertung
  • Keine Nebenwirkungen (alles ist rein, IO / etc passiert über Monaden)
  • Unglaublich ausdrucksstarkes statisches Typsystem

sowie einige andere Aspekte, die sich von vielen gängigen Sprachen unterscheiden (aber von einigen geteilt werden):

  • funktional
  • signifikante Leerzeichen
  • Typ abgeleitet

Wie einige andere Poster geantwortet haben, bedeutet die Kombination all dieser Funktionen, dass Sie die Programmierung auf eine ganz andere Art und Weise betrachten. Daher ist es schwierig, ein Beispiel (oder eine Reihe von Beispielen) zu finden, das dies dem Joe-Mainstream-Programmierer angemessen vermittelt. Es ist eine experimentelle Sache. (Um eine Analogie zu ziehen, ich kann Ihnen Fotos von meiner Reise nach China 1970 zeigen, aber nachdem Sie die Fotos gesehen haben, werden Sie immer noch nicht wissen, wie es war, während dieser Zeit dort gelebt zu haben. Ebenso kann ich Ihnen einen Haskell zeigen 'quicksort', aber du wirst immer noch nicht wissen, was es bedeutet, ein Haskeller zu sein.)


17
Ich bin mit Ihrem ersten Satz nicht einverstanden. Ich war anfangs sehr beeindruckt von einigen Beispielen für Haskell-Code und was mich wirklich überzeugt hat, dass es sich lohnt zu lernen, war dieser Artikel: cs.dartmouth.edu/~doug/powser.html Aber natürlich ist dies für einen Mathematiker / Physiker interessant. Ein Programmierer, der sich mit realen Dingen befasst, würde dieses Beispiel lächerlich finden.
Rafael S. Calsaverini

2
@ Rafael: Das wirft die Frage auf, "wovon würde ein Programmierer, der sich mit realen Dingen befasst, beeindruckt sein"?
JD

Gute Frage! Ich bin kein "realer" Programmierer, daher weiß ich nicht, was sie mögen. hahaha ... Ich weiß, was Physiker und Mathematiker mögen. : P
Rafael S. Calsaverini

27

Was Haskell wirklich auszeichnet, ist der Aufwand für die Durchsetzung der funktionalen Programmierung. Sie können in nahezu jeder Sprache in einem funktionalen Stil programmieren, aber es ist allzu einfach, auf den ersten Blick darauf zu verzichten. Haskell erlaubt es Ihnen nicht, die funktionale Programmierung aufzugeben, daher müssen Sie sie zu ihrer logischen Schlussfolgerung führen, die ein endgültiges Programm ist, über das man leichter nachdenken kann, und eine ganze Klasse der dornigsten Arten von Fehlern umgeht.

Wenn es darum geht, ein Programm für den realen Gebrauch zu schreiben, fehlt Haskell möglicherweise auf praktische Weise, aber Ihre endgültige Lösung ist besser, wenn Sie Haskell von Anfang an kennen. Ich bin definitiv noch nicht da, aber bisher war es viel aufschlussreicher, Haskell zu lernen, als zu sagen, Lisp war auf dem College.


1
Nun, es gibt immer die Möglichkeit, immer und nur die ST-Monade zu benutzen und / oder unsafePerformIOfür Leute, die nur die Welt brennen sehen wollen;)
sara

22

Ein Teil der Aufregung ist, dass Reinheit und statische Typisierung Parallelität in Kombination mit aggressiven Optimierungen ermöglichen. Parallele Sprachen sind jetzt heiß, und Multicore ist etwas störend.

Haskell bietet Ihnen mehr Optionen für Parallelität als so ziemlich jede Allzwecksprache sowie einen schnellen, nativen Code-Compiler. Es gibt wirklich keine Konkurrenz mit dieser Art der Unterstützung für parallele Stile:

Wenn Sie also daran interessiert sind, dass Ihr Multicore funktioniert, hat Haskell etwas zu sagen. Ein guter Anfang ist das Tutorial von Simon Peyton Jones zur parallelen und gleichzeitigen Programmierung in Haskell .


"zusammen mit einem schnellen, nativen Code-Compiler"?
JD

Ich glaube, Dons bezieht sich auf GHCI.
Gregory Higley

3
@ Jon: shootout.alioth.debian.org/u32/... Haskell tut ziemlich gut auf der Schießerei, zum Beispiel.
Peaker

4
@ Jon: Der Shootout-Code ist sehr alt und stammt aus einer fernen Vergangenheit, in der GHC weniger ein optimierender Compiler war. Es zeigt jedoch, dass Haskell-Code bei Bedarf auf niedrigem Niveau arbeiten kann . Neuere Lösungen im Shootout sind idiomatischer und dennoch schnell.
Peaker

1
@ GregoryHigley Es gibt einen Unterschied zwischen GHCI und GHC.
Jeremy List

18

Software Transactional Memory ist eine ziemlich coole Möglichkeit, mit Parallelität umzugehen. Es ist viel flexibler als das Weiterleiten von Nachrichten und nicht wie Mutexe anfällig für Deadlocks. Die Implementierung von STM durch GHC gilt als eine der besten.


18

Ich habe das letzte Jahr damit verbracht, Haskell zu lernen und ein ziemlich großes und komplexes Projekt darin zu schreiben. (Das Projekt ist ein automatisiertes Optionshandelssystem, und alles, von den Handelsalgorithmen bis zum Parsen und Verarbeiten von Marktdaten-Feeds auf niedriger Ebene und hoher Geschwindigkeit, wird in Haskell durchgeführt.) Es ist wesentlich präziser und verständlicher (für diejenigen mit angemessener Hintergrund) als eine Java-Version wäre, sowie extrem robust.

Möglicherweise war der größte Gewinn für mich die Fähigkeit, den Kontrollfluss durch Dinge wie Monoide, Monaden usw. zu modularisieren. Ein sehr einfaches Beispiel wäre das Bestellmonoid; in einem Ausdruck wie

c1 `mappend` c2 `mappend` c3

wo c1usw. Rückkehr LT, EQoder GT, c1zurückkehr EQUrsachen der Expression fortzusetzen, zu bewerten c2; if gibt c2zurück LToder GTdas ist der Wert des Ganzen und c3wird nicht ausgewertet. Diese Art von Dingen wird in Dingen wie monadischen Nachrichtengeneratoren und Parsern, in denen ich verschiedene Arten von Zuständen herumtrage, unterschiedliche Abbruchbedingungen habe oder für einen bestimmten Anruf entscheiden möchte, ob Abbruch wirklich bedeutet, erheblich komplexer und komplexer "keine weitere Verarbeitung" oder bedeutet "am Ende einen Fehler zurückgeben, aber die Verarbeitung fortsetzen, um weitere Fehlermeldungen zu sammeln".

Dies alles ist etwas, das einige Zeit und wahrscheinlich einige Mühe braucht, um es zu lernen, und daher kann es für diejenigen, die diese Techniken noch nicht kennen, schwierig sein, ein überzeugendes Argument dafür zu liefern. Ich denke, dass das All About Monads- Tutorial eine ziemlich eindrucksvolle Demonstration einer Facette davon bietet, aber ich würde nicht erwarten, dass jemand, der nicht bereits mit dem Material vertraut ist, es beim ersten oder sogar beim dritten sorgfältigen Lesen "bekommt".

Wie auch immer, es gibt auch viele andere gute Sachen in Haskell, aber dies ist eine wichtige Sache, die ich nicht so oft erwähnt sehe, wahrscheinlich weil sie ziemlich komplex ist.


2
Sehr interessant! Wie viele Zeilen Haskell-Code sind insgesamt in Ihr automatisiertes Handelssystem eingeflossen? Wie sind Sie mit Fehlertoleranz umgegangen und welche Leistungsergebnisse haben Sie erzielt? Ich habe kürzlich gedacht, dass Haskell das Potenzial hat, für die Programmierung mit geringer Latenz gut zu sein ...
JD

12

Ein interessantes Beispiel finden Sie unter: http://en.literateprograms.org/Quicksort_(Haskell)

Interessant ist es, die Implementierung in verschiedenen Sprachen zu betrachten.

Was Haskell zusammen mit anderen funktionalen Sprachen so interessant macht, ist die Tatsache, dass Sie anders über das Programmieren nachdenken müssen. Beispielsweise verwenden Sie im Allgemeinen keine for- oder while-Schleifen, sondern die Rekursion.

Wie oben erwähnt, zeichnen sich Haskell und andere funktionale Sprachen durch parallele Verarbeitungs- und Schreibanwendungen für die Arbeit mit mehreren Kernen aus.


2
Rekursion ist die Bombe. das und Mustervergleich.
Ellery Newcomer

1
For- und while-Schleifen loszuwerden ist für mich der schwierigste Teil, wenn ich in einer funktionalen Sprache schreibe. :)
James Black

4
Das Lernen, in Rekursion statt in Schleifen zu denken, war auch für mich der schwierigste Teil. Als es endlich einsank, war es eine der größten Programmier-Epiphanien, die ich je hatte.
Chris Connett

8
Außer dass der funktionierende Haskell-Programmierer selten primitive Rekursion verwendet; Meistens verwenden Sie Bibliotheksfunktionen wie map und foldr.
Paul Johnson

18
Ich finde es interessanter, dass Hoares ursprünglicher Quicksort-Algorithmus anscheinend in diese auf fehlenden Listen basierende Form verfälscht wurde, damit nutzlos ineffiziente Implementierungen in Haskell "elegant" geschrieben werden konnten. Wenn Sie versuchen, eine echte (in-place) Quicksort in Haskell zu schreiben, werden Sie feststellen, dass es höllisch hässlich ist. Wenn Sie versuchen, in Haskell eine wettbewerbsfähige generische Quicksortierung zu schreiben, werden Sie feststellen, dass dies aufgrund langjähriger Fehler im Garbage Collector von GHC tatsächlich unmöglich ist. Ich begrüße Quicksort als gutes Beispiel für den Glauben der Haskell-Bettler, IMHO.
JD

8

Ich konnte Ihnen kein Beispiel geben, ich bin ein OCaml-Typ, aber wenn ich mich in einer Situation wie Ihnen befinde, greift die Neugier einfach und ich muss einen Compiler / Interpreter herunterladen und ausprobieren. Auf diese Weise lernen Sie wahrscheinlich viel mehr über die Stärken und Schwächen einer bestimmten funktionalen Sprache.


1
Vergessen Sie nicht, den Quellcode des Compilers zu lesen. Das gibt Ihnen auch viele wertvolle Informationen.
JD

7

Eine Sache, die ich beim Umgang mit Algorithmen oder mathematischen Problemen sehr cool finde, ist Haskells inhärente träge Bewertung von Berechnungen, die nur aufgrund ihrer strengen funktionalen Natur möglich ist.

Wenn Sie beispielsweise alle Primzahlen berechnen möchten, können Sie verwenden

primes = sieve [2..]
    where sieve (p:xs) = p : sieve [x | x<-xs, x `mod` p /= 0]

und das Ergebnis ist tatsächlich eine unendliche Liste. Aber Haskell wird es von links nach rechts auswerten. Solange Sie nicht versuchen, etwas zu tun, das die gesamte Liste erfordert, können Sie es trotzdem verwenden, ohne dass das Programm im Unendlichen hängen bleibt, wie zum Beispiel:

foo = sum $ takeWhile (<100) primes

Das summiert alle Primzahlen unter 100. Das ist aus mehreren Gründen schön. Zuerst muss ich nur eine Primfunktion schreiben, die alle Primzahlen generiert, und dann bin ich ziemlich bereit, mit Primzahlen zu arbeiten. In einer objektorientierten Programmiersprache müsste ich der Funktion mitteilen, wie viele Primzahlen vor der Rückkehr berechnet werden sollen, oder das Verhalten einer unendlichen Liste mit einem Objekt emulieren. Eine andere Sache ist, dass Sie im Allgemeinen Code schreiben, der ausdrückt, was Sie berechnen möchten und nicht in welcher Reihenfolge die Dinge bewertet werden sollen - stattdessen erledigt der Compiler dies für Sie.

Dies ist nicht nur für unendliche Listen nützlich, sondern wird auch verwendet, ohne dass Sie es ständig wissen, wenn nicht mehr als nötig ausgewertet werden muss.


2
Das ist nicht ganz richtig; Mit dem Yield Return-Verhalten von C # (einer objektorientierten Sprache) können Sie auch unendliche Listen deklarieren, die bei Bedarf ausgewertet werden.
Jeff Yates

2
Guter Punkt. Sie haben Recht und ich sollte vermeiden, so kategorisch anzugeben, was in anderen Sprachen getan werden kann und was nicht. Ich denke, mein Beispiel war fehlerhaft, aber ich denke immer noch, dass Sie etwas von Haskells fauler Bewertung profitieren: Es ist standardmäßig wirklich da und ohne Anstrengung des Programmierers. Und das liegt meiner Meinung nach an seiner funktionellen Natur und dem Fehlen von Nebenwirkungen.
Waxwing

8
Vielleicht interessiert es Sie zu lesen, warum "Sieb" nicht das Sieb von Eratosthenes ist: lambda-the-ultimate.org/node/3127
Chris Conway

@ Chris: Danke, das war eigentlich ein ziemlich interessanter Artikel! Die obige Primzahlfunktion ist nicht die, die ich für meine eigenen Berechnungen verwendet habe, da sie schmerzhaft langsam ist. Trotzdem bringt der Artikel einen guten Punkt auf den Punkt, dass das Überprüfen aller Zahlen auf Mod wirklich ein anderer Algorithmus ist.
Waxwing

6

Ich stimme anderen zu, dass es nicht der beste Weg ist, Haskell zu zeigen, wenn man ein paar kleine Beispiele sieht. Aber ich werde trotzdem welche geben. Hier ist eine blitzschnelle Lösung für die Probleme 18 und 67 des Euler-Projekts , bei der Sie aufgefordert werden, den Pfad mit der maximalen Summe von der Basis bis zur Spitze eines Dreiecks zu finden:

bottomUp :: (Ord a, Num a) => [[a]] -> a
bottomUp = head . bu
  where bu [bottom]     = bottom
        bu (row : base) = merge row $ bu base
        merge [] [_] = []
        merge (x:xs) (y1:y2:ys) = x + max y1 y2 : merge xs (y2:ys)

Hier ist eine vollständige, wiederverwendbare Implementierung des BubbleSearch- Algorithmus von Lesh und Mitzenmacher. Ich habe damit große Mediendateien für die Archivierung auf DVD ohne Verschwendung gepackt:

data BubbleResult i o = BubbleResult { bestResult :: o
                                     , result :: o
                                     , leftoverRandoms :: [Double]
                                     }
bubbleSearch :: (Ord result) =>
                ([a] -> result) ->       -- greedy search algorithm
                Double ->                -- probability
                [a] ->                   -- list of items to be searched
                [Double] ->              -- list of random numbers
                [BubbleResult a result]  -- monotone list of results
bubbleSearch search p startOrder rs = bubble startOrder rs
    where bubble order rs = BubbleResult answer answer rs : walk tries
            where answer = search order
                  tries  = perturbations p order rs
                  walk ((order, rs) : rest) =
                      if result > answer then bubble order rs
                      else BubbleResult answer result rs : walk rest
                    where result = search order

perturbations :: Double -> [a] -> [Double] -> [([a], [Double])]
perturbations p xs rs = xr' : perturbations p xs (snd xr')
    where xr' = perturb xs rs
          perturb :: [a] -> [Double] -> ([a], [Double])
          perturb xs rs = shift_all p [] xs rs

shift_all p new' [] rs = (reverse new', rs)
shift_all p new' old rs = shift_one new' old rs (shift_all p)
  where shift_one :: [a] -> [a] -> [Double] -> ([a]->[a]->[Double]->b) -> b
        shift_one new' xs rs k = shift new' [] xs rs
          where shift new' prev' [x] rs = k (x:new') (reverse prev') rs
                shift new' prev' (x:xs) (r:rs) 
                    | r <= p    = k (x:new') (prev' `revApp` xs) rs
                    | otherwise = shift new' (x:prev') xs rs
                revApp xs ys = foldl (flip (:)) ys xs

Ich bin sicher, dieser Code sieht aus wie zufälliger Kauderwelsch. Wenn Sie jedoch Mitzenmachers Blogeintrag lesen und den Algorithmus verstehen, werden Sie erstaunt sein, dass es möglich ist, den Algorithmus in Code zu packen, ohne etwas über das zu sagen, wonach Sie suchen.

Nachdem ich Ihnen einige Beispiele gegeben habe, nach denen Sie gefragt haben, werde ich sagen, dass der beste Weg, um Haskell zu schätzen, darin besteht, das Papier zu lesen, das mir die Ideen gab, die ich zum Schreiben des DVD-Packers brauchte: Warum funktionale Programmierung von John Hughes wichtig ist. Das Papier ist eigentlich älter als Haskell, aber es erklärt auf brillante Weise einige der Ideen, die Menschen wie Haskell ausmachen.


5

Für mich ist die Attraktion von Haskell das Versprechen der vom Compiler garantierten Korrektheit. Auch wenn es sich um reine Teile des Codes handelt.

Ich habe viel wissenschaftlichen Simulationscode geschrieben und mich so oft gefragt , ob meine vorherigen Codes einen Fehler enthielten, der viele aktuelle Arbeiten ungültig machen könnte.


6
Wie garantiert es die Richtigkeit?
Jonathan Fischoff

Die reinen Teile des Codes sind viel sicherer als die unreinen. Das Maß an Vertrauen / Aufwand ist viel höher.
RPG

1
Was hat dir diesen Eindruck gemacht?
JD

5

Ich finde, dass ich für bestimmte Aufgaben mit Haskell unglaublich produktiv bin.

Der Grund liegt in der prägnanten Syntax und der einfachen Prüfung.

So sieht die Syntax der Funktionsdeklaration aus:

foo a = a + 5

Das ist der einfachste Weg, eine Funktion zu definieren.

Wenn ich das Gegenteil schreibe

inverseFoo a = a - 5

Ich kann überprüfen, ob es für jede zufällige Eingabe eine Umkehrung ist, indem ich schreibe

prop_IsInverse :: Double -> Bool
prop_IsInverse a = a == (inverseFoo $ foo a)

Und von der Kommandozeile aus anrufen

jonny @ ubuntu: runhaskell quickCheck + names fooFileName.hs

Dadurch wird überprüft, ob alle Eigenschaften in meiner Datei gespeichert sind, indem die Eingaben hundertmal zufällig getestet werden.

Ich denke nicht, dass Haskell die perfekte Sprache für alles ist, aber wenn es darum geht, kleine Funktionen zu schreiben und zu testen, habe ich nichts Besseres gesehen. Wenn Ihre Programmierung eine mathematische Komponente hat, ist dies sehr wichtig.


Welche Probleme lösen Sie und welche anderen Sprachen haben Sie ausprobiert?
JD

1
Echtzeit-3D-Grafiken für das Handy und das iPad.
Jonathan Fischoff

3

Wenn Sie sich mit dem Typensystem in Haskell beschäftigen können, halte ich das für eine ziemliche Errungenschaft.


1
Was gibt es zu bekommen? Wenn Sie müssen, denken Sie an "data" == "class" und "typeclass" = "interface" / "role" / "trait". Einfacher geht es nicht. (Es gibt nicht einmal "null", um Sie durcheinander zu bringen. Null ist ein Konzept, das Sie selbst in Ihren Typ
einbauen

8
Es gibt eine ganze Menge zu bekommen, Jrockway. Während Sie und ich es relativ einfach finden, finden viele Leute - sogar viele Entwickler - bestimmte Arten von Abstraktionen sehr schwer zu verstehen. Ich kenne viele Entwickler, die die Idee von Zeigern und Referenzen in mehr Mainstream-Sprachen immer noch nicht ganz verstehen, obwohl sie sie jeden Tag verwenden.
Gregory Higley

2

Es gibt keine Schleifenkonstrukte. Nicht viele Sprachen haben dieses Merkmal.


17
ghci>: m + Control.Monad ghci> forM_ [1..3] print 1 2 3
sastanin

1

Ich stimme denen zu, die sagten, dass funktionale Programmierung Ihr Gehirn dazu bringt, die Programmierung aus einem anderen Blickwinkel zu betrachten. Ich habe es nur als Hobbyist benutzt, aber ich denke, es hat meine Herangehensweise an ein Problem grundlegend verändert. Ich glaube nicht, dass ich mit LINQ annähernd so effektiv gewesen wäre, ohne Haskell ausgesetzt gewesen zu sein (und Generatoren und Listenverständnisse in Python verwendet zu haben).


-1

Um eine konträre Sichtweise zu äußern: Steve Yegge schreibt, dass Hindely-Milner-Sprachen nicht die Flexibilität haben, die erforderlich ist, um gute Systeme zu schreiben :

HM ist sehr hübsch, in einem völlig nutzlosen formalen mathematischen Sinne. Es handhabt einige Rechenkonstrukte sehr gut; Besonders praktisch ist der Mustervergleichsversand in Haskell, SML und OCaml. Es ist nicht überraschend, dass einige andere gängige und äußerst wünschenswerte Konstrukte bestenfalls umständlich behandelt werden, aber sie erklären diese Szenarien, indem sie sagen, dass Sie sich irren und sie eigentlich nicht wollen. Sie wissen, Dinge wie, oh, Variablen setzen.

Haskell ist es wert, gelernt zu werden, aber es hat seine eigenen Schwächen.


5
Zwar ist es sicher richtig, dass starke Typsysteme im Allgemeinen erfordern, dass Sie sich an sie halten (das macht ihre Stärke nützlich), aber es ist auch so, dass viele (die meisten?) Bestehenden HM-basierten Typsysteme tatsächlich eine Art von 'haben. Escape Hatch 'wie im Link beschrieben (nehmen Sie Obj.magic in O'Caml als Beispiel, obwohl ich es nur als Hack verwendet habe); In der Praxis benötigt man jedoch für viele Arten von Programmen niemals ein solches Gerät.
Zach Snow

3
Die Frage, ob das Setzen von Variablen "wünschenswert" ist, hängt davon ab, wie viel Schmerz es ist, die alternativen Konstrukte zu verwenden, und wie viel Schmerz durch die Verwendung von Variablen verursacht wird. Damit soll nicht das gesamte Argument verworfen werden, sondern darauf hingewiesen werden, dass die Aussage "Variablen sind ein äußerst wünschenswertes Konstrukt" als Axiom nicht die Grundlage eines schlüssigen Arguments ist. Es ist einfach so, wie die meisten Leute lernen, wie man programmiert.
GTD

5
-1: Steves Aussagen sind teilweise veraltet, aber meistens nur völlig sachlich falsch. Die entspannte Wertebeschränkung von OCaml und das Typsystem von .NET sind einige offensichtliche Gegenbeispiele zu seinen Aussagen.
JD

4
Steve Yegge hat eine unvernünftige Biene in seiner Haube, die sich mit statischer Typisierung befasst, und das meiste, was er darüber sagt, ist nicht nur falsch, er spricht es auch bei jeder verfügbaren Gelegenheit an (und sogar bei einigen nicht verfügbaren). Sie tun gut daran, nur Ihrer eigenen Erfahrung in dieser Hinsicht zu vertrauen.
ShreevatsaR

3
Obwohl ich mit Yegge in Bezug auf statische und dynamische Typisierung nicht einverstanden bin, hat Haskell den Typ Data.Dynamic. Wenn Sie dynamisch tippen möchten, können Sie es haben!
Jrockway
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.