Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the multiple line in Haskell ? an operator , a function , something else?

Tags:

haskell

I am very new to Haskell , and I must say I am puzzled

I am using GHCi prelude

First attemps to create a factorial

Prelude> factorial 0 = 1
Prelude> factorial n = n*factorial(n-1)
Prelude> factorial 2
*** Exception: stack overflow

ends up in stack overflow. Obviously recursion has not stopped.

Prelude> :t factorial
factorial :: Num t => t -> t

Then reading this post How to define a function in ghci across multiple lines?

I found out that I have to use either multiple line edition or braces (by the way is this an operator ?)

Prelude> let { fact 0 = 1 ; fact n = n * fact (n-1) }
Prelude> fact 5
120
Prelude> ::t fact
fact :: (Eq p, Num p) => p -> p

or

Prelude> :{
Prelude| facto 0 = 1
Prelude| facto n = n*facto(n-1)
Prelude| :}
Prelude> facto 4
24
Prelude> :t facto
facto :: (Eq p, Num p) => p -> p

So, my question is , why the first one is wrong, what happen in this case, why the 2nd and the 3rd are working, and from the result of the :t function, they seem to at least result in the exact same definition.

like image 898
sandwood Avatar asked Nov 07 '17 09:11

sandwood


3 Answers

why the first one is wrong, what happen in this case

Because you defined two functions that had the same name.

First you define:

factorial 0 = 1

later you define:

factorial n = n*factorial(n-1)

But Haskell will see the second factorial as a variable that is scoped more local, so the second function definition, hides the previous one. The first line (factorial 0 = 1) is thus no longer part of the definition. Thus Haskell will evaluate factorial 2 -> 2 * factorial 1 -> 2 * 1 * factorial 0 -> 2 * 1 * 0 * factorial (-1) -> ....

why the 2nd and the 3rd are working

Because here you define a single function, and Haskell interpretets the two clauses as two clauses of the same function. The fact that with :t function you obtain the same, is just coincidence.

Note that the above only is valid for GHCi. If you work with a ghc compiler, it will of course see all your statements as part of the same function definition. In case you mix the clauses of two functions (e.g. first a 0 = 0, then b 0 = 0, and then a n = n) it will error about *multiple definitions for the same function).

like image 144
Willem Van Onsem Avatar answered Nov 01 '22 18:11

Willem Van Onsem


In earlier versions of ghci, lines defining functions would have to be prepended with let. As of a recent version, the let is implicit in any definition line.
What this means is, each line defining your function is treated as its own let expression, so each subsequent line replaces (or 'shadows') the previous definition, instead of adding to it as would occur in a regular Haskell program.

The :{ and :} in ghci allow you to write several lines as a single input, whereas usually each line is treated independently in ghci. This means that you can write a multiline let expression:

:{
let fact 0 = 1
    fact n = n * fact (n - 1)
:}

Or, in later versions, this is equivalent:

:{
fact 0 = 1
fact n = n * fact (n - 1)
:}

And the function fact will be defined as one would expect in a regular Haskell program.

like image 37
Zoey Hewll Avatar answered Nov 01 '22 18:11

Zoey Hewll


When you define

Prelude> factorial 0 = 1
Prelude> factorial n = n*factorial(n-1)
Prelude> factorial 2
*** Exception: stack overflow

The first definition of factorial is discarded, so the function is defined as

Prelude> factorial n = n*factorial(n-1)

So you don't have a statement to end the recursion anymore.

like image 1
Reactormonk Avatar answered Nov 01 '22 19:11

Reactormonk