Wie definiere ich eine Funktion in ghci über mehrere Zeilen hinweg?

161

Ich versuche, eine einfache Funktion zu definieren, die mehrere Zeilen in ghci umfasst. Nehmen Sie als Beispiel Folgendes:

let abs n | n >= 0 = n
          | otherwise = -n

Bisher habe ich versucht, nach der ersten Zeile die Eingabetaste zu drücken:

Prelude> let abs n | n >= 0 = n
Prelude>           | otherwise = -n
<interactive>:1:0: parse error on input `|'

Ich habe auch versucht, die Befehle :{und zu verwenden :}, komme aber nicht weit:

Prelude> :{
unknown command ':{'
use :? for help.

Ich verwende GHC Interactive Version 6.6 für Haskell 98 unter Linux. Was fehlt mir?

Peter McG
quelle
20
Bitte aktualisieren Sie Ihre GHC-Installation. GHC 6.6 ist fast 5 Jahre alt! Die neuesten Versionen von Haskell sind hier: haskell.org/platform
Don Stewart
Mögliches Duplikat mehrzeiliger Befehle in GHCi
mmmmmm
1
@Mark Dieses OP hat bereits versucht, Lösungen für dieses Problem zu finden. Dieses Problem ist auf ein veraltetes Ghci zurückzuführen, nicht auf mangelndes Wissen darüber, was zu tun ist. Lösung hier: Upgrade. Lösung dort: verwenden :{, :}.
AndrewC

Antworten:

125

Für Wachen (wie in Ihrem Beispiel) können Sie sie einfach alle in eine Zeile setzen und es funktioniert (Wachen kümmern sich nicht um Abstände)

let abs n | n >= 0 = n | otherwise = -n

Wenn Sie Ihre Funktion mit mehreren Definitionen schreiben möchten, deren Muster mit den Argumenten übereinstimmt, wie folgt:

fact 0 = 1
fact n = n * fact (n-1)

Dann würden Sie geschweifte Klammern mit Semikolons verwenden, die die Definitionen trennen

let { fact 0 = 1 ; fact n = n * fact (n-1) }
newacct
quelle
258

GHCi verfügt jetzt über einen mehrzeiligen Eingabemodus, der aktiviert ist mit: set + m. Beispielsweise,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800
Karakfa
quelle
39
Durch das Festlegen des mehrzeiligen Modus ghciverhält es sich in dieser Hinsicht ähnlich wie der Python-Interpreter. Sehr angenehm! Sie können in der Tat eine .ghciDatei in Ihrem Home-Verzeichnis erstellen, in die Sie den :set +mMultiline-Modus einfügen, der bei jedem Start zum Standard wird ghci!
kqr
2
Das ist wirklich großartig. Aber ich habe bemerkt, dass, wenn ich meine Eingabeaufforderung mit :set prompt "λ "den fortgesetzten Zeilen setze, Preludestatt sagen λ. Wie kann man das umgehen?
Abhillman
2
Hier finden Sie den Patch zum Definieren einer neuen Fortsetzungsaufforderung ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa
4
Um zu verhindern, dass Prelude in Fortsetzungszeilen angezeigt wird, fügen Sie Folgendes hinzu: set prompt2 "|" in Ihrer .ghci.
Nick
12
Sie können das Einrücken mit einem Trailing vollständig vermeiden let. letGeben letSie einfach ein gefolgt von einem Zeilenumbruch ein: ⏎. Dann fac 0 = 1⏎. Dann fac n = n * fac (n-1)⏎ ⏎ und du bist fertig!
Island_jack
62

Dan ist richtig, aber :{und :}muss jeder in seiner eigenen Zeile erscheinen:

> :{ 
> let foo a b = a +
>           b
> :}
> :t foo
foo :: (Num a) => a -> a -> a

Dies interagiert auch mit der Layoutregel. Wenn Sie also die Do-Notation verwenden, ist es möglicherweise einfacher, Klammern und Semikolons explizit zu verwenden. Diese Definition schlägt beispielsweise fehl:

> :{
| let prRev = do
|   inp <- getLine
|   putStrLn $ reverse inp
| :}
<interactive>:1:18:
    The last statement in a 'do' construct must be an expression

Aber es funktioniert, wenn Klammern und Semikolons hinzugefügt werden:

> :{
| let prRev = do {
|   inp <- getLine;
|   putStrLn $ reverse inp;
| }
| :}
> :t prRev
prRev :: IO ()

Dies ist nur dann wirklich wichtig, wenn Definitionen aus einer Datei eingefügt werden, bei denen sich der Einzug ändern kann.

Justin Bailey
quelle
Dies funktioniert nicht, wenn Sie eine Zeile haben, die mit '=' endet (mit der Definition in der nächsten Zeile), zumindest in Version 7.6.3.
AdamC
1
Vielleicht schlägt dies fehl, weil die zweite und dritte Zeile des Let nicht genug eingerückt sind ...? (Zwei weitere Leerzeichen.)
Evi1M4chine
7

Wenn Sie GHC nicht nur für :{und aktualisieren möchten, :}müssen Sie alles in eine Zeile schreiben:

> let abs' n | n >= 0 = n | otherwise = -n

Mir ist keine einzelne Definition in Haskell bekannt, die in mehreren Zeilen geschrieben werden muss . Das Obige funktioniert tatsächlich in GHCi:

> :t abs'
abs' :: (Num a, Ord a) => a -> a

Für andere Ausdrücke, wie z. B. doBlöcke, müssen Sie die Nicht-Layout-Syntax mit geschweiften Klammern und Semikolons (eugh) verwenden.

CA McCann
quelle
0

Ich verwende GHCi, Version 8.2.1 unter macOS Catalina 10.15.2. Im Folgenden werden sowohl die Funktionstypdeklaration als auch die Schutzvorrichtungen zusammengestellt. Beachten Sie, dass die vertikalen Balken links für mehrere GHCi-Zeilen gelten.

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7
Goldener Daumen
quelle
1
Wenn Sie verwenden :{und vor Ihrer Typdeklaration :}nichts angeben müssen let , müssen Sie keine zweite und nachfolgende Zeile einrücken.
Davida
Vielen Dank davidA. Genau das hatte ich gesucht, aber nicht gefunden.
Goldener Daumen
0

Es sieht so aus, als würden beide Zeilen gleichzeitig eingefügt oder die Strg-Eingabe für jede neue Zeile verwendet, um alles zusammenzuhalten, zumindest unter https://repl.it/languages/haskell . Am Anfang der zweiten Zeile sehen Sie 2 Punkte. Oder legen Sie es in eine Datei und: laden Sie die Datei (: l main). Wie kommt es, dass abs mit negativen Zahlen nicht funktioniert? Oh, du musst die Zahl in Klammern setzen.

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
js2010
quelle