I am studying Haskell and I am learning what is an abstraction, substitution (beta equivalence), application, free and bound variables (alpha equivalence), but I have some doubts resolving these exercises, I don't know if my solutions are correct.
Make the following substitutions
1. (λ x → y x x) [x:= f z]
Sol. (\x -> y x x) =>α (\w -> y w w) =>α (\w -> x w w) =>β (\w -> f z w w)
2. ((λ x → y x x) x) [y:= x]
Sol. ((\x -> y x x)x) =>α (\w -> y w w)[y:= x] = (\w -> x w w)
3. ((λ x → y x) (λ y → y x) y) [x:= f y]
Sol. aproximation, i don't know how to do it: ((\x -> y x)(\y -> y x) y) =>β
(\x -> y x)y x)[x:= f y] =>β y x [x:= f y] = y f y
4. ((λ x → λ y → y x x) y) [y:= f z]
Sol aproximation, ((\x -> (\y -> (y x x))) y) =>β ((\y -> (y x x)) y) =>α ((\y -> (y x x)) f z)
Another doubt that I have is if can I run these expressions on this website? It is a Lambda Calculus Calculator but I do not know how to run these tests.
1. (λ x → y x x) [x:= f z]
Sol. (\x -> y x x) =>α (\w -> y w w) =>α (\w -> x w w) =>β (\w -> f z w w)
No, you can't rename y, it's free in (λ x → y x x). Only bound variables can be (consistently) α-renamed. But only free variables can be substituted, and there's no free x in that lambda term.
2. ((λ x → y x x) x) [y:= x]
Sol. ((\x -> y x x)x) =>α (\w -> y w w)[y:= x] = (\w -> x w w)
Yes, substituting x for y would allow it to be captured by the λ x, so you indeed must α-rename the x in (λ x → y x x) first to some new unique name as you did, but you've dropped the application to the free x for some reason. You can't just omit parts of a term, so it's ((\w -> y w w) x)[y:= x]. Now perform the substitution. Note you're not asked to perform the β-reduction of the resulting term, just the substitution.
I'll leave the other two out. Just follow the rules carefully. It's easy if you rename all bound names to unique names first, even if the renaming is not strictly required, for instance
((λ x → y x) (λ y → y x) y) [x:= f y] -->
((λ w → y w) (λ z → z x) y) [x:= f y]
The "unique" part includes also the free variables used in the substitution terms, that might get captured after being substituted otherwise (i.e. without the renaming being performed first, in the terms in which they are being substituted). That's why we had to rename the bound y in the above term, -- because y appears free in the substitution term. We didn't have to rename the bound x but it made it easier that way.
Related
I am starting learning haskell and today in my class our teacher has resolved an excercise which we have to subtitute the expressions given. One of those expressions which was resolved by the teacher was the following:
(\ x. x) (\ y. y + x) [x: = z + z]
(\ x. x) (\ y. y + (z + z))
It seems that the teacher only replaced the free x on the right with the new value asked, but it didn't reduce the expression. What i see on this expression (\ x. x) (\ y. y + x) its that is a Redox. So what i would do first is reduce and then substitute.
So in my notebook i wrote this steps to get the solution:
(\ x. x) (\ y. y + x) [x: = z + z]
(\ y. y + x) [x: = z + z]
(\ y. y + (z + z))
My doubt: is it my solution correct? Can i first Reduce expression and then substitute? Thanks
I am trying to understand the meaning of the following 2 lambda expressions in Haskell:
f = \x -> x (\y -> x y)
g = \x -> (\y -> y) x
I tried to convert them, and I got this:
f x y = x x y
g x y = y x
Is this correct? I assumed the arguments of both functions have to be x and y, as they are both found in a lambda expression in the function description. I basically understood it this way: f(x) = x f(y) and f(y) = y x. And for g, g(x) = g(y) x and g(y) = y. But as I am new to Haskell, I'm not very confident with these types of conversion. If not correct, what would be a correct conversion?
Neither is correct. Your solution uses the functions
f x y = x x y
g x y = y x
which actually mean
f = \x -> (\y -> x x y)
g = \x -> (\y -> y x)
and those differ from the original expressions
f = \x -> x (\y -> x y)
g = \x -> (\y -> y) x
The above two equations can be rewritten as
f x = x (\y -> x y)
g x = (\y -> y) x
But from here, there is no way to turn the remaining lambdas into more arguments for f or g. At best, we can simplify them using beta/eta conversion and get
f x = x x -- eta (\y -> x y) = x
g x = x -- beta (\y -> y) x = x
(Also see the comment below by Will Ness, who points out that through an additional eta expansion in f we could reach the OP's definition. Still, that is incidental.)
Finally, note that Haskell will not accept f x = x x since that can not be typed, unless we use rank-2 types and explicitly provide a type annotation like f :: (forall a. a) -> b. The original code f = \x -> x (\y -> x y) suffers from the same issue. That would also be fine in untyped languages, e.g. the untyped lambda calculus in programming languages theory.
The :type command at the GHCi prompt is your friend. Let's take your second example first
λ> :type let g = \x -> (\y -> y) x in g
let g = \x -> (\y -> y) x in g :: p -> p
So g is well-typed and is a convoluted way to write an identity function :: p -> p. Specifically, g takes some x and applies an identity function (\y -> y) to x, resulting in x. GHCi in giving the type uses a fresh type name p, to avoid confusion. No your g x y = ... is not equivalent. (Check it with :type.)
You can abbreviate :type to just :t. Then let's take your first example.
λ> :t let f = \x -> x (\y -> x y) in f
* Occurs check: cannot construct the infinite type: t2 ~ t2 -> t3
* In the first argument of `x', namely `(\ y -> x y)'
In the expression: x (\ y -> x y)
In the expression: \ x -> x (\ y -> x y)
* Relevant bindings include
x :: t2 -> t3 (bound at <interactive>:1:10)
f :: (t2 -> t3) -> t3 (bound at <interactive>:1:5)
Errk. Is your suggested f the same as that?
λ> :t let f x y = x x y in f
* Occurs check: cannot construct the infinite type:
t3 ~ t3 -> t4 -> t5
* In the first argument of `x', namely `x'
It at least looks like a similar error message. What are these t2, t3, t4, t5? Again it's GHCi using fresh names for the types, to avoid confusion.
Looking at the let f = ..., GHCi sees x is applied to something, so it gives x :: t2 -> t3 where t2 is the type of its argument, t3 is the return type. It also sees f = \x -> x (blah). So the return type of f must be whatever x returns, i.e. t3, and the argument to f is x. So f :: (t2 -> t3) -> t3.
Inside the (blah), there's x applied to something. So the something (i.e. y) must be the type of x's argument, and the return type must be x's return type. I.e. (\y -> x y) :: t2 -> t3. Errk: then we must have x's argument type same as that, because x is applied to it. And the way we write 'same as' is with ~.
Then the error message tells you GHCi is trying to make sense of t2 ~ (t2 -> t3). (-> binds tighter than ~.) And if you try to subsitute that equivalence for t2 into the RHS you'll get t2 ~ (((... -> t3) -> t3)-> t3) ad infinitum.
Your suggested equivalent for f x y = is not equivalent (the message/typing is a little different). But they're both infinite types, so not allowed.
Hello is there a way to write point free style when using infix notation?
f::Int->Int->Int->Int
f a b=(+) (a+b)
Why you cannot do something like this ?
f::Int->Int->Int->Int
f a b=(a+b) +
or
f a b= (a+b) `+`
Can you not combine operators in point free style like e.g?
ptfree::Int->Int->Int->Int
ptfree=(+) (+)
I mean you can chop arguments of functions like fold but why not for operator arguments?
Well since you need to pass two parameters, we can use what is known as the "surprised owl operator". This is basically a composition of parameters. So we can use:
f = ((.).(.)) (+) (+)
Or we can more inline the operator like:
f = ((+) .) . (+)
The owl operator ((.).(.)) f g basically is short for \x y -> f (g x y)
How does this work?
The canonical form of the "surprised owl operator" is:
= ((.) . (.))
------------- (canonical form)
(.) (.) (.)
So we can now replace the (.)s with corresponding lambda expressions:
(\f g x -> f (g x)) (.) (.)
So now we can perform some replacements:
(\f g x -> f (g x)) (.) (.)
-> (\x -> (.) ((.) x))
-> (\x -> (\q r y -> q (r y)) ((.) x))
-> (\x -> (\r y -> ((.) x) (r y)))
-> (\x r y -> ((.) x) (r y))
-> (\x r y -> ((\s t u -> s (t u)) x) (r y))
-> (\x r y -> (\t u -> x (t u)) (r y))
-> (\x r y -> (\u -> x ((r y) u)))
-> \x r y u -> x ((r y) u))
-> \x r y u -> x (r y u)
So basically it means that our surprised owl operator, is equal to:
surprised_owl :: (y -> z) -> (a -> b -> y) -> a -> b -> z
surprised_owl f g x y = f (g x y) -- renamed variables
And if we now specialize this with the fuctions provided (two times (+)), we get:
f = surprised_owl (+) (+)
so:
f x y = (+) ((+) x y)
You must compose (+) with (+) twice, for it to be completely point-free: f = ((+) .) . (+)
Recall that composition is defined as
(f . g) x = f (g x)
or, equivalently:
(f . g) = \x -> f (g x)
So, if you look at the composition f = ((+) .) . (+) and work backwards using the definition of (.):
f = ((+) .) . (+)
f = \x -> ((+) .) ((+) x) -- definition of (.)
f = \y -> (\x -> (+) (((+) x) y)) -- definition of (.)
f x y = (+) (((+) x) y) -- a simpler way to write this
f x y z = (+) (((+) x) y) z -- explicitly add in the final argument (eta expansion)
f x y z = ((+) x y) + z -- rewrite as infix
f x y z = (x + y) + z -- rewrite as infix
and you see we end up with what we started before we tried to make it point-free, so we know that this definition works. Going the other way through the steps above, roughly bottom-to-top, could give you an idea of how you might find such a point-free definition of a function like f.
When you "leave off" multiple arguments from the "end" like this, you usually must compose multiple times. Working through a few similar functions should help build intuition for this.
Note: I wouldn't generally recommend using this sort of point-free (when it complicates things) in production code.
In programming language J, is a train of verbs always associative? If it is, Are there any proofs?
No, a train of verbs is not associative and this follows the definitions. For example, a fork is
(f g h) y = (f y) g (h y)
but
(f (g h)) y = y f ((g h) y) = y f (y g (h y))
which can also be written as y f y g h y. And
((f g) h) y = y (f g) (h y) = y f (g (h y))
which can also be written as y f g h y.
Those three are completely different things.
Train in J is right associative, and the minimum group is a fork. Only when it cannot make a fork, it makes a hook. So
vvvvv = (vv(vvv)),
And
vvvv= (v(vvv)).
I now understand the type signature of s (s k):
s (s k) :: ((t1 -> t2) -> t1) -> (t1 -> t2) -> t1
And I can create examples that work without error in the Haskell WinGHCi tool:
Example:
s (s k) (\g -> 2) (\x -> 3)
returns 2.
Example:
s (s k) (\g -> g 3) successor
returns 4.
where successor is defined as so:
successor = (\x -> x + 1)
Nonetheless, I still don't have an intuitive feel for what s (s k) does.
The combinator s (s k) takes any two functions f and g. What does s (s k) do with f and g? Would you give me the big picture on what s (s k) does please?
Alright, let's look at what S (S K) means. I'm going to use these definitions:
S = \x y z -> x z (y z)
K = \x y -> x
S (S K) = (\x y z -> x z (y z)) ((\x y z -> x z (y z)) (\a b -> a)) -- rename bound variables in K
= (\x y z -> x z (y z)) (\y z -> (\a b -> a) z (y z)) -- apply S to K
= (\x y z -> x z (y z)) (\y z -> (\b -> z) (y z)) -- apply K to z
= (\x y z -> x z (y z)) (\y z -> z) -- apply (\_ -> z) to (y z)
= (\x y z -> x z (y z)) (\a b -> b) -- rename bound variables
= (\y z -> (\a b -> b) z (y z)) -- apply S to (\a b -> b)
= (\y z -> (\b -> b) (y z)) -- apply (\a b -> b) to z
= (\y z -> y z) -- apply id to (y z)
As you can see, it's just ($) with more specific type.