What are the pros and cons of explicit function definition as opposed to where notation in Haskell?
Explicit function definition:
foo :: Integer -> Integer
foo a = bar a
where
bar :: Integer -> Integer
bar a = Some code here
as opposed to:
foo :: Integer -> Integer
foo a = bar a
bar :: Integer -> Integer
bar a = Some code here
Why would I use one over the other? Is there anything to be aware of with regards to efficiency? Security? Code reusability? Code readability?
If your auxiliary function is not going to be used anywhere else, it's better not to pollute the namespace and use a local definition.
When your outer function has only one top-level "pattern", the where clause can simplify the definition of the auxiliary function because the parameters of the outer function will be in scope.
outer x v z f = undefined
where
inner i = i + x + v + z + f
versus
outer x v z f = undefined
inner x v z f i = i + x + v + z + f
If your function has more than one top-level "pattern", then you can't share bindings across patters using where. You have to define a top-level binding.
Certain ways of using where can incur in non-obvious performance penalties. This definition (taken from the HaskellWiki article on let vs where)
fib x = map fib' [0 ..] !! x
where
fib' 0 = 0
fib' 1 = 1
fib' n = fib (n - 1) + fib (n - 2)
is slower than this one:
fib = (map fib' [0 ..] !!)
where
fib' 0 = 0
fib' 1 = 1
fib' n = fib (n - 1) + fib (n - 2)
and also slower than defining fib' at the top-level.
The reason is that, in the first definition, a new fib' is created for each invocation of fib. Explained here.
If you need bar only in the scope of foo, it is more readable and better information hiding to declare it in "where". If bar should be reusable outside of foo, the it needs to be declared parallel to foo.
Related
I am working on the following exercise:
Define a function libDiv which computes the list of natural divisors of some positive integer.
First define libDivInf, such that libDivInf n i is the list of divisors of n which are lesser than or equal to i
libDivInf : int -> int -> int list
For example:
(liDivInf 20 4) = [4;2;1]
(liDivInf 7 5) = [1]
(liDivInf 4 4) = [4;2;1]
Here's is my attempt:
let liDivInf : int -> int -> int list = function
(n,i) -> if i = 0 then [] (*ERROR LINE*)
else
if (n mod i) = 0 (* if n is dividable by i *)
then
i::liDivInf n(i-1)
else
liDivInf n(i-1);;
let liDiv : int -> int list = function
n -> liDivInf n n;;
I get:
ERROR: this pattern matches values of type 'a * 'b ,but a pattern
was expected which matches values of type int
What does this error mean? How can I fix it?
You've stated that the signature of liDivInf needs to be int -> int -> int list. This is a function which takes two curried arguments and returns a list, but then bound that to a function which accepts a single tuple with two ints. And then you've recursively called it in the curried fashion. This is leading to your type error.
The function keyword can only introduce a function which takes a single argument. It is primarily useful when you need to pattern-match on that single argument. The fun keyboard can have multiple arguments specified, but does not allow for pattern-matching the same way.
It is possible to write a function without using either.
let foo = function x -> x + 1
Can just be:
let foo x = x + 1
Similarly:
let foo = function x -> function y -> x + y
Can be written:
let foo x y = x + y
You've also defined a recursive function, but not included the rec keyword. It seems you're looking for something much more like the following slightly modified version of your attempt.
let rec liDivInf n i =
if i = 0 then
[]
else if (n mod i) = 0 then
i::liDivInf n (i-1)
else
liDivInf n (i-1)
In Unison, functions are identified by the hashes of their ASTs instead of by their names.
Their documentation and their FAQs have given some explanations of the mechanism.
However, the example presented in the link is not clear to me how the hashing actually works:
They used an example
f x = g (x - 1)
g x = f (x / 2)
which in the first step of their hashing is converted to the following:
$0 =
f x = $0 (x - 1)
g x = $0 (x / 2)
Doesn't this lose information about the definitions.
For the two following recursively-defined functions, how can the hashing distinguish them:
# definition 1
f x = g (x / 2)
g x = h (x + 1)
h x = f (x * 2 - 7)
# definition 2
f x = h (x / 2)
g x = f (x + 1)
h x = g (x * 2 - 7)
In my understanding, brutally converting all calling of f g and h to $0 would make the two definitions undistinguishable from each other. What am I missing?
The answer is that the form in the example (with $0) is not quite accurate. But in short, there's a special kind of hash (a "cycle hash") which is has the form #h.n where h is the hash of all the mutually recursive definitions taken together, and n is a number from 0 to the number of terms in the cycle. Each definition in the cycle gets the same hash, plus an index.
The long answer:
Upon seeing cyclical definitions, Unison captures them in a binding form called Cycle. It's a bit like a lambda, but introduces one bound variable for each definition in the cycle. References within the cycle are then replaced with those variables. So:
f x = g (x - 1)
g x = f (x / 2)
Internally becomes more like (this is not valid Unison syntax):
$0 = Cycle f g ->
letrec
[ x -> g (x - 1)
, x -> f (x / 2) ]
It then hashes each of the lambdas inside the letrec and sorts them by that hash to get a canonical order. Then the whole cycle is hashed. Then these "cycle hashes" of the form #h.n get introduced at the top level for each lambda (where h is the hash of the whole cycle and n is the canonical index of each term), and the bound variables get replaced with the cycle hashes:
#h.0 = x -> #h.1 (x - 1)
#h.1 = x -> #h.0 (x / 2)
f = #h.0
g = #h.1
I am trying to learn Haskell programming language by trying to figure out some pieces of code.
I have these 2 small functions but I have no idea how to test them on ghci.
What parameters should I use when calling these functions?
total :: (Integer -> Integer) -> Integer -> Integer
total function count = foldr(\x count -> function x + count) 0 [0..count]
The function above is supposed to for the given value n, return f 0 + f 1 + ... + f n.
However when calling the function I don't understand what to put in the f part. n is just an integer, but what is f supposed to be?
iter :: Int -> (a -> a) -> (a -> a)
iter n f
| n > 0 = f . iter (n-1) f
| otherwise = id
iter' :: Int -> (a -> a) -> (a -> a)
iter' n = foldr (.) id . replicate n
This function is supposed to compose the given function f :: a -> a with itself n :: Integer times, e.g., iter 2 f = f . f.
Once again when calling the function I don't understand what to put instead of f as a parameter.
To your first question, you use any value for f such that
f 0 + f 1 + ... + f n
indeed makes sense. You could use any numeric function capable of accepting an Integer argument and returning an Integer value, like (1 +), abs, signum, error "error", (\x -> x^3-x^2+5*x-2), etc.
"Makes sense" here means that the resulting expression has type ("typechecks", in a vernacular), not that it would run without causing an error.
To your second question, any function that returns the same type of value as its argument, like (1+), (2/) etc.
Im pretty much new to Haskell, so if Im missing key concept, please point it out.
Lets say we have these two functions:
fact n
| n == 0 = 1
| n > 0 = n * (fact (n - 1))
The polymorphic type for fact is (Eq t, Num t) => t -> t Because n is used in the if condition and n must be of valid type to do the == check. Therefor t must be a Number and t can be of any type within class constraint Eq t
fib n
| n == 1 = 1
| n == 2 = 1
| n > 2 = fib (n - 1) + fib (n - 2)
Then why is the polymorphic type of fib is (Eq a, Num a, Num t) => a -> t?
I don't understand, please help.
Haskell always aims to derive the most generic type signature.
Now for fact, we know that the type of the output, should be the same as the type of the input:
fact n | n == 0 = 1
| n > 0 = n * (fact (n - 1))
This is due to the last line. We use n * (fact (n-1)). So we use a multiplication (*) :: a -> a -> a. Multiplication thus takes two members of the same type and returns a member of that type. Since we multiply with n, and n is input, the output is of the same type as the input. Since we use n == 0, we know that (==) :: Eq a => a -> a -> Bool so that means that that input type should have Eq a =>, and furthermore 0 :: Num a => a. So the resulting type is fact :: (Num a, Eq a) => a -> a.
Now for fib, we see:
fib n | n == 1 = 1
| n == 2 = 1
| n > 2 = fib (n - 1) + fib (n - 2)
Now we know that for n, the type constraints are again Eq a, Num a, since we use n == 1, and (==) :: Eq a => a -> a -> Bool and 1 :: Num a => a. But the input n is never directly used in the output. Indeed, the last line has fib (n-1) + fib (n-2), but here we use n-1 and n-2 as input of a new call. So that means we can safely asume that the input type and the output type act independently. The output type, still has a type constraint: Num t: this is since we return 1 for the first two cases, and 1 :: Num t => t, and we also return the addition of two outputs: fib (n-1) + fib (n-2), so again (+) :: Num t => t -> t -> t.
The difference is that in fact, you use the argument directly in an arithmetic expression which makes up the final result:
fact n | ... = n * ...
IOW, if you write out the expanded arithmetic expression, n appears in it:
fact 3 ≡ n * (n-1) * (n-2) * 1
This fixes that the argument must have the same type as the result, because
(*) :: Num n => n -> n -> n
Not so in fib: here the actual result is only composed of literals and of sub-results. IOW, the expanded expression looks like
fib 3 ≡ (1 + 1) + 1
No n in here, so no unification between argument and result required.
Of course, in both cases you also used n to decide how this arithmetic expression looks, but for that you've just used equality comparisons with literals, whose type is not connected to the final result.
Note that you can also give fib a type-preservig signature: (Eq a, Num a, Num t) => a -> t is strictly more general than (Eq t, Num t) => t -> t. Conversely, you can make a fact that doesn't require input- and output to be the same type, by following it with a conversion function:
fact' :: (Eq a, Integral a, Num t) => a -> t
fact' = fromIntegral . fact
This doesn't make a lot of sense though, because Integer is pretty much the only type that can reliably be used in fact, but to achieve that in the above version you need to start out with Integer. Hence if anything, you should do the following:
fact'' :: (Eq t, Integral a, Num t) => a -> t
fact'' = fact . fromIntegral
This can then be used also as Int -> Integer, which is somewhat sensible.
I'd recommend to just keep the signature (Eq t, Num t) => t -> t though, and only add conversion operations where it's actually needed. Or really, what I'd recommend is to not use fact at all – this is a very expensive function that's hardly ever really useful in practice; most applications that naïvely end up with a factorial really just need something like binomial coefficients, and those can be implemented more efficiently without a factorial.
Eventually what I want is what x represents:
let x = (something, (myfunc1 para1));;
so that when calling x, I get a tuple, but when calling (snd x) para, I will get a return value of myfunc1 para.
What I'm trying is like this:
let myfunc2 para1 para2 =
let myfunc1 para2 = ... in
( (fst para1), (myfunc1 para2) );;
And I want to call myfunc2 like this:
let x = myfunc2 para1 to get what I described above. However, what I get is just a function which when called with para1 will return a regular tuple, not a (something, function) tuple
You have a useless para2 parameter in your definition. The correct way is:
let myfunc2 para1 =
let x = ... in
let myfunc1 para2 = ... in
( x, myfunc1 );;
But it would help if we could speak about a concrete example. You are misunderstanding something obvious, but I do not know what.
Here is a concrete example. Suppose we want a function f which accepts a number n and returns a pair (m, g) where m is the square of n and g is a function which adds n to its argument:
let f n =
let m = n * n in
let g k = n + k in
(m, g)
Or shorter:
let f n = (n * n, fun k => n + k)
Now to use this, we can do:
let x = f 10 ;;
fst x ;; (* gives 100 *)
snd x ;; (* gives <fun> *)
snd x 5 ;; (* gives 15, and is the same thing as (snd x) 5 *)
Now let us consider the following bad solution in which we make the kind of mistake you have made:
let f_bad n k =
let m = n * n in
let g k = n + k in
(m, g k)
Now f_bad wants two arguments. If we give it just one, we will not get a pair but a function expecting the other argument. And when we give it that argument, it will return a pair of two integers because (m, g k) means "make a pair whose first component is the integer m and the second component is g applied to k, so that is an integer, too."
Another point worth making is that you are confusing yourself by calling two different things para2. In our definition of f_bad we also confuse ourselves by calling two different things k. The k appearing in the definition of g is not the same as the other k. It is better to call the two k's different things:
let f_bad n k1 =
let m = n * n in
let g k2 = n + k2 in
(m, g k1)
Now, does that help clear up the confusion?