简体   繁体   中英

Understanding the Haskell type of this expression

I was doing a Haskell types exercise and this one has stumped me. The provided expression is:

f2 f g h = h.g.f

And the type for f2 is apparently:

f2 :: (a -> b1) -> (b1 -> b) -> (b -> c) -> a -> c

This seems overly complicated for such a short expression. Can someone explain why this makes sense as the type?

I find these “determine the type of such and such expression” generally a bit backwards. Types should always come first: you want to program a solution to some task, you formulate the problem description as a type signature. Then you go ahead and actually write an implementation.

In this case, you'd start with the problem: I have three functions f , g and h , and a value of type that I can pass to f . Furthermore, the functions have pairwise matching result/argument type. Hence the signature

f2 :: (α -> β) -> (β -> γ) -> (γ -> δ) -> α -> δ

You could now go on and implement this in explicit-pointed form, ie

f2 f g h x = h (g (f x))

which is still quite brief. After all, it's quite a simple task!

But in Haskell you can make it even shorter, by using the standard composition operator . . The fact that the final implementation is so extremely short is basically just down to the fact that f2 does essentially the same thing as . , just twice. So this isn't more surprising than if you have a very complex task with a complicated type signature, but discover some library that contains a function which does almost that exact task. Obviously, invoking that ready-build function will give you a much shorter implementation than the task complexity would suggest, but the complexity is merely deferred to the library function.

Why do you think it's complicated? It's just a function that takes three functions (of matching types) and returns a new one.

I've renamed b1 to b and updated other names, for consistency. So here is a slightly edited version:

f2 :: (a -> b) -> (b -> c) -> (c -> d) -> a -> d

  • Here, f2 takes f which has type a -> b . Meaning, it's a function, with some input of some type a ( a can be just anything, no restrictions here) and some return value of type b .
  • Then f2 takes g which input's type must match f 's output, so it's b -> c . It cannot be, like, e -> c (where e is something different from b ), or the code won't make sense as it won't be possible to compose f . g f . g .
  • And exactly the same goes for the third argument, h , with type c -> d .
  • The result of function composition (what f2 returns) is a new function that takes in whatever f does and returns whatever h returns, so it's a -> d . With this we've covered the whole type definition.

Basically, it's a relatively long definition, but I think it's of a very simple nature.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM