Why is the type of this function (a -> a) -> a?
Prelude> let y f = f (y f)
Prelude> :t y
y :: (t -> t) -> t
Shouldn't it be an infinite/recursive type? I was going to try and put into words what I think it's type should be, but I just can't do it for some reason.
y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS?
I don't get how f (y f) resolves to a value. The following makes a little more sense to me:
Prelude> let y f x = f (y f) x
Prelude> :t y
y :: ((a -> b) -> a -> b) -> a -> b
But it's still ridiculously confusing. What's going on?
Well,
yhas to be of type(a -> b) -> c, for somea,bandcwe don't know yet; after all, it takes a function,f, and applies it to an argument, so it must be a function taking a function.Since
y f = f x(again, for somex), we know that the return type ofymust be the return type offitself. So, we can refine the type ofya bit: it must be(a -> b) -> bfor someaandbwe don't know yet.To figure out what
ais, we just have to look at the type of the value passed tof. It'sy f, which is the expression we're trying to figure out the type of right now. We're saying that the type ofyis(a -> b) -> b(for somea,b, etc.), so we can say that this application ofy fmust be of typebitself.So, the type of the argument to
fisb. Put it all back together, and we get(b -> b) -> b— which is, of course, the same thing as(a -> a) -> a.Here's a more intuitive, but less precise view of things: we're saying that
y f = f (y f), which we can expand to the equivalenty f = f (f (y f)),y f = f (f (f (y f))), and so on. So, we know that we can always apply anotherfaround the whole thing, and since the "whole thing" in question is the result of applyingfto an argument,fhas to have the typea -> a; and since we just concluded that the whole thing is the result of applyingfto an argument, the return type ofymust be that offitself — coming together, again, as(a -> a) -> a.