191

I'm trying to define any simple function that spans multiple lines in ghci, take the following as an example:

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

So far I've tried pressing Enter after the first line:

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

I've also attempted to use the :{ and :} commands but I don't get far:

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

I'm using GHC Interactive version 6.6 for Haskell 98 on Linux, what am I missing?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Peter McG
  • 18,857
  • 8
  • 45
  • 53
  • 23
    Please upgrade your GHC installation. GHC 6.6 is nearly 5 years old! The latest versions of Haskell are here: http://haskell.org/platform – Don Stewart May 17 '10 at 01:30
  • possible duplicate of [Multi-line commands in GHCi](http://stackoverflow.com/questions/8443035/multi-line-commands-in-ghci) – mmmmmm May 07 '14 at 11:22
  • 3
    @Mark This OP already tried the solutions to that problem. This problem is due to an out-of-date ghci, not lack of knowledge of what to do. Solution here: upgrade. Solution there: use `:{`, `:}`. – AndrewC May 08 '14 at 15:13

7 Answers7

297

GHCi now has a multiline-input mode, enabled with :set +m. For example,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
karakfa
  • 66,216
  • 7
  • 41
  • 56
  • 49
    Setting multiline mode makes `ghci` behave much like the Python interpreter in this regard. Very convenient! You can in fact create a `.ghci` file in your home directory in which you put `:set +m` and multiline mode will become the default every time you start `ghci`! – kqr Nov 05 '13 at 21:04
  • 3
    This is really awesome. But I have noticed that when I set my prompt using `:set prompt "λ "` the continued lines say `Prelude` instead of `λ`. Any way to get around this? – abhillman Jun 18 '14 at 06:02
  • 2
    See here for the patch to define a new continuation prompt https://ghc.haskell.org/trac/ghc/ticket/7509#no1 – karakfa Jun 18 '14 at 13:22
  • 6
    To prevent Prelude appearing on continuation lines, also add :set prompt2 "| " in your .ghci. – Nick Sep 11 '16 at 21:10
  • 18
    You can *completely* avoid indentation using a trailing `let`. Simply type a `let` followed by a newline: `let` ⏎. Then `fac 0 = 1` ⏎. Then `fac n = n * fac (n-1)` ⏎ ⏎ and you're done! – Iceland_jack Sep 17 '16 at 19:34
  • 2
    `:set prompt2 "| "` now seems to be `:set prompt-cont "| "`. Not sure when the change was made, but I'm using GHC 8.6.3. – David Tchepak Feb 01 '19 at 03:48
  • 1
    I believe @Iceland_jack’s [comment](https://stackoverflow.com/questions/2846050/how-to-define-a-function-in-ghci-across-multiple-lines#comment66413573_19798581) makes this an excellent answer, because 1) tab invokes auto-complete by default so indentation is not straight-forward; 2) `let` used in this way is really just a trick of convenience for ghci. – Heath Raftery Oct 18 '21 at 05:23
139

For guards (like your example), you can just put them all on one line and it works (guards do not care about spacing)

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

If you wanted to write your function with multiple definitions that pattern match on the arguments, like this:

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

Then you would use braces with semicolons separating the definitions

let { fact 0 = 1 ; fact n = n * fact (n-1) }
Brian61354270
  • 8,690
  • 4
  • 21
  • 43
newacct
  • 119,665
  • 29
  • 163
  • 224
76

Dan is correct, but :{ and :} must each appear on their own line:

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

This also interacts with the layout rule, so when using do-notation it might be easier to use braces and semi-colons explicitly. For example, this definition fails:

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

But it works when braces and semi-colons are added:

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

This will only really matter when pasting definitions from a file, where indentation might change.

Justin Bailey
  • 1,487
  • 11
  • 15
  • This doesn't work if you have a line ending in '=' (with the definition following on the next line), at least in version 7.6.3. – AdamC May 22 '14 at 14:15
  • 1
    Perhaps this fails, because the second and third line of the let are not indented enough…? (Two more spaces.) – Evi1M4chine May 08 '16 at 02:44
23

It looks like :{ and :} are a pretty new feature. You may need to upgrade GHC.

Edit: confirmed, see http://www.haskell.org/ghc/docs/6.8.2/html/users_guide/release-6-8-2.html

Dan
  • 10,990
  • 7
  • 51
  • 80
8

If you don't want to upgrade GHC just for :{ and :}, you'll need to write it all on one line:

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

I'm not aware of any single definition in Haskell that must be written on multiple lines. The above does indeed work in GHCi:

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

For other expressions, such as do blocks, you'll need to use the non-layout syntax with curly braces and semicolons (eugh).

C. A. McCann
  • 76,893
  • 19
  • 209
  • 302
2

It looks like pasting both lines at once or using control-enter for each new line keeps it all together, at least at https://repl.it/languages/haskell. You'll see 2 dots in the beginning of the second line. Or put it in a file and :load the file (:l main). How come abs doesn't work with negative numbers? Oh you have to put parentheses around the number.

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
js2010
  • 23,033
  • 6
  • 64
  • 66
0

I'm using GHCi, version 8.2.1 on macOS Catalina 10.15.2. The following is how I put both function type declaration and guards together. Note the vertical bars on the left are for GHCi multiple lines.

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7
Golden Thumb
  • 2,531
  • 21
  • 20
  • 2
    If you use `:{` and `:}` you don't need to specify `let ` before your type declaration, meaning that you don't need to indent second and subsequent lines. – davidA May 12 '20 at 02:27
  • Thank you very much davidA. That's exactly what I had been looking for but failed to find. – Golden Thumb May 12 '20 at 03:29