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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With