I'm going through the book "Haskell programming from first principles" and although the authors try to explain in detail how to reduce expressions, I still have trouble understanding how to read some expressions in the examples provided.
Let's assume the below expression:
(λx.x) Then if I understand things correctly this can be read as: "A lambda function, that accepts an argument x and returns (basically translating . as "returns") the same value x.
Now supposing that that we have the below expression:
(λxy.xy), how do we read that expression in plain English? To make it even more complex the authors then expand (λxy.xy) to (λxy.xy)(λz.a) 1. How are these z and a appearing to the above expression? I was hoping that if I can properly transform the expression to plain English I'd be able to understand where z and a come from.
In lambda calculus, values that are next to each other imply that the first value is being called as a function with the second value as an argument. (λxy.xy) is shorthand for (λx.λy.xy), which means a function that takes an argument x then an argument y, and calls x with argument y. (if you're wondering why there's a function returning a function, it's due to currying). To figure out what (λxy.xy)(λz.a) 1 means, we have to take it step by step:
Undo the shorthand: (λx. λy. xy) (λz. a) 1
Apply first function (λx): (λy. (λz. a) y) 1
Apply second function (λy): (λz. a) 1
Apply third function (λz): a
So, we end up with whatever a is (probably an externally defined constant).
Related
I'm studying project euler solutions and this is the solution of problem 4, which asks to
Find the largest palindrome made from the product of two 3-digit
numbers
problem_4 =
maximum [x | y<-[100..999], z<-[y..999], let x=y*z, let s=show x, s==reverse s]
I understand that this code creates a list such that x is a product of all possible z and y.
However I'm having a problem understanding what does s do here. Looks like everything after | is going to be executed everytime a new element from this list is needed, right?
I don't think I understand what's happening here. Shouldn't everything to the right of | be constraints?
A list comprehension is a rather thin wrapper around a do expression:
problem_4 = maximum $ do
y <- [100..999]
z <- [y..999]
let x = y*z
let s = show x
guard $ s == reverse s
return x
Most pieces translate directly; pieces that aren't iterators (<-) or let expressions are treated as arguments to the guard function found in Control.Monad. The effect of guard is to short-circuit the evaluation; for the list monad, this means not executing return x for the particular value of x that led to the false argument.
I don't think I understand what's happening here. Shouldn't everything to the right of | be constraints?
No, at the right part you see an expression that is a comma-separated (,) list of "parts", and every part is one of the following tree:
an "generator" of the form somevar <- somelist;
a let statement which is an expression that can be used to for instance introduce a variable that stores a subresult; and
expressions of the type boolean that act like a filter.
So it is not some sort of "constraint programming" where one simply can list some constraints and hope that Haskell figures it out (in fact personally that is the difference between a "programming language" and a "specification language": in a programming language you have "control" how the data flows, in a specification language, that is handled by a system that reads your specifications)
Basically an iterator can be compared to a "foreach" loop in many imperative programming languages. A "let" statement can be seen as introducing a temprary variable (but note that in Haskell you do not assign variable, you declare them, so you can not reassign values). The filter can be seen as an if statement.
So the list comprehension would be equivalent to something in Python like:
for y in range(100, 1000):
for z in range(y, 1000):
x = y * z
s = str(x)
if x == x[::-1]:
yield x
We thus first iterate over two ranges in a nested way, then we declare x to be the multiplication of y and z, with let s = show x, we basically convert a number (for example 15129) to its string counterpart (for example "15129"). Finally we use s == reverse s to reverse the string and check if it is equal to the original string.
Note that there are more efficient ways to test Palindromes, especially for multiplications of two numbers.
With GHC version 8.0.2 the following program:
import Debug.Trace
f=trace("f was called")$(+1)
main = do
print $ f 1
print $ f 2
outputs:
f was called
2
3
Is it the expected behaviour? If yes, why? I expected the string f was called to be printed twice, one before 2 and one before 3.
Same result on TIO: Try it online!
EDIT
But this program:
import Debug.Trace
f n=trace("f was called:"++show n)$n+1
main = do
print $ f 1
print $ f 2
outputs:
f was called:1
2
f was called:2
3
Try it online!
I suspect those behaviours have something to do with laziness, but my questions remain: is this the expected behaviour and, if yes, why?
Hackage asserts this:
The trace function outputs the trace message given as its first
argument, before returning the second argument as its result.
I don't see it in the first example.
EDIT 2 Third example based on #amalloy comments:
import Debug.Trace
f n=trace "f was called"$n+1
main = do
print $ f 1
print $ f 2
outputs:
f was called
2
f was called
3
Your trace prints when defining f, not when calling it. If you want the trace to happen as part of the call, you should make sure it is not evaluated until a parameter is received:
f x = trace "f was called" $ x + 1
Also, when I run your TIO I don't see the trace appearing at all. trace is not really a reliable way to print things, because it cheats the IO model that the language is built on. The most subtle changes in evaluation order can disturb it. Of course for debugging you can use it, but as even this simple example demonstrates it is not guaranteed to help much.
In your edit, you quote the documentation of trace:
The trace function outputs the trace message given as its first
argument, before returning the second argument as its result.
And indeed this is exactly what happens in your program! When defining f,
trace "f was called" $ (+ 1)
needs to be evaluated. First, "f was called" is printed. Then, trace evaluates to, and returns, (+ 1). This is the final value of the trace expression, and therefore (+ 1) is what f is defined as. The trace has vanished, see?
It is indeed a result of laziness.
Laziness means that merely defining a value doesn't mean it will be evaluated; that will only happen if it's needed for something. If it's not needed, the code that would actually produce it doesn't "do anything". If a particular value is needed the code is run, but only the first time it would be needed; if there are other references to the same value and it is used again, those uses will just directly use the value that was produced the first time.
You have to remember that functions are values in every sense of the term; everything that applies to ordinary values also applies to functions. So your definition of f is simply writing an expression for a value, the expression's evaluation will be deferred until the value of f is actually needed, and as it's needed twice the value (function) the expression computes will be saved and reused the second time.
Lets look at it in more detail:
f=trace("f was called")$(+1)
You're defining a value f with a simple equation (not using any syntactic sugar for writing arguments on the left hand side of the equation, or providing cases via multiple equations). So we can simply take the right hand side as a single expression that defines the value f. Just defining it does nothing, it sits there until you call:
print $ f 1
Now print needs its argument evaluated, so this is forcing the expression f 1. But we can't apply f to 1 without first forcing f. So we need to figure out what function the expression trace "f was called" $ (+1) evaluates to. So trace is actually called, does its unsafe IO printing and f was called appears at the terminal, and then trace returns its second argument: (+1).
So now we know what function f is: (+1). f will now be a direct reference to that function, with no need to evaluate the original code trace("f was called")$(+1) if f is called again. Which is why the second print does nothing.
This case is quite different, even though it might look similar:
f n=trace("f was called:"++show n)$n+1
Here we are using the syntactic sugar for defining functions by writing arguments on the left hand side. Let's desugar that to lambda notation to see more clearly what the actual value being bound to f is:
f = \n -> trace ("f was called:" ++ show n) $ n + 1
Here we've written a function value directly, rather than an expression that can be evaluated to result in a function. So when f needs to be evaluated before it can be called on 1, the value of f is that whole function; the trace call is inside the function instead of being the thing that is called to result in a function. So trace isn't called as part of evaluating f, it's called as part of evaluating the application f 1. If you saved the result of that (say by doing let x = f 1) and then printed it multiple times, you'd only see the one trace. But the when we come to evaluate f 2, the trace call is still there inside the function that is the value of f, so when f is called again so is trace.
I'm learning basic Haskell so I can configure Xmonad, and I ran into this code snippet:
newKeys x = myKeys x `M.union` keys def x
Now I understand what the M.union in backticks is and means. Here's how I'm interpreting it:
newKeys(x) = M.union(myKeys(x),???)
I don't know what to make of the keys def x. Is it like keys(def(x))? Or keys(def,x)? Or is def some sort of other keyword?
It's keys(def,x).
This is basic Haskell syntax for function application: first the function itself, then its arguments separated by spaces. For example:
f x y = x + y
z = f 5 6
-- z = 11
However, it is not clear what def is without larger context.
In response to your comment: no, def couldn't be a function that takes x as argument, and then the result of that is passed to keys. This is because function application is left-associative, which basically means that in any bunch of things separated by spaces, only the first one is the function being applied, and the rest are its arguments. In order to express keys(def(x)), one would have to write keys (def x).
If you want to be super technical, then the right way to think about it is that all functions have exactly one parameter. When we declare a function of two parameters, e.g. f x y = x + y, what we really mean is that it's a function of one parameter, which returns another function, to which we can then pass the remaining parameter. In other words, f 5 6 means (f 5) 6.
This idea is kind of one of the core things in Haskell (and any ML offshoot) syntax. It's so important that it has its own name - "currying" (after Haskell Curry, the mathematician).
While studying for a Functional Programming exam, I came across the following question from a previous test:
t1 = (reverse . take 2 . words . \ _ -> name)"!"
The task is to write the output of the statement. The variable name refers to the student's name, written in the form "Smith, John". If I enter the statement into WinHugs, I get the following output:
["John","Smith,"]
I understand what the functions reverse, take and words are doing and I understand how the . operator connects them. What I don't understand is what is happening here:
\ _ -> name
What are the slash, underscore and "arrow" for? Also, what does the exclamation point in quotation marks do? (nothing?)
It's a lambda function that discards its (only) argument (i.e. "!") and yields name.
As another lambda example, the following would be a lambda function that squares its argument:
\x -> x * x
The \ is the notation used to introduce a lambda function.
The _ means "variable about whose name we do not care".
The -> separates the lambda function's arguments from the expression used to specify its result.
What you are seeing there is an anonymous function, or lambda function (that name comes from lambda calculus). The backslash tells you that you are starting the function. The underscore says that the function takes one argument and ignores it. The arrow points from the argument list to the result - in this case, it ends up ignoring its argument and returning the name. Essentially, \_ -> name is the same as const name.
A constant anonymous function: which ever the argument, return name.
Haskell's lambda expressions (i.e. anonymous functions) come in this form:
\x -> f x
where x is an argument, and f x an expression using this argument. The special variable _ matches anything and treats it as unimportant.
The "slash" is part of a lambda function, the underscore is a "wildcard" used in patterns (it is discarded). The arrow is another part of the lambda function. The function \ _ -> name returns the name, regardless of input, so the "!" does nothing but provide (unused) input to the function.
I am implementing an impure untyped lambda-calculus interpreter in Haskell.
I'm presently stuck on implementing "alpha-congruence" (also called "alpha-equivalence" or "alpha-equality" in some textbooks). I want to be able to check whether two lambda-expressions are equal or not equal to each other. For example, if I enter the following expression into the interpreter it should yield True (\ is used to indicate the lambda symbol):
>\x.x == \y.y
True
The problem is understanding whether the following lambda-expressions are considered alpha-equivalent or not:
>\x.xy == \y.yx
???
>\x.yxy == \z.wzw
???
In the case of \x.xy == \y.yx I would guess that the answer is True. This is because \x.xy => \z.zy and \y.yx => \z.zy and the right-hand sides of both are equal (where the symbol => is used to denote alpha-reduction).
In the cae of \x.yxy == \z.wzw I would likewise guess that the answer is True. This is because \x.yxy => \a.yay and \z.wzw => \a.waw which (I think) are equal.
The trouble is that all of my textbooks' definitions state that only the names of the bound variables need to be changed for two lambda-expressions to be considered equal. It says nothing about the free variables in an expression needing to be renamed uniformly also. So even though y and w are both in their correct places in the lambda-expressions, how would the program "know" that the first y represents the first w and the second y represents the second w. I would need to be consistent about this in an implementation.
In short, how would I go about implementing an error-free version of a function isAlphaCongruent? What are the exact rules that I need to follow in order for this to work?
I would prefer to do this without using de Bruijn indices.
You are misunderstanding: different free variables are not alpha equivalent. So y /= x, and \w.wy /= \w.wx, and \x.xy /= \y.yx. Similarly, \x.yxy /= \z.wzw because y /= w.
Your book says nothing about free variables being allowed to be uniformly renamed because they are not allowed to be uniformly renamed.
(Think of it this way: if I haven't yet told you the definition of not and id, would you expect \x. not x and \x. id x to be equivalent? I sure hope not!)