简体   繁体   中英

Understanding this type in Haskell?

I'm having some trouble understanding, how this type declaration works.

The type is: (a -> b) -> (b -> c) -> (c -> d) -> a -> d

So, to me I interpret this as a function that takes a function and that function takes another function which outputs a value d.

So, this is how I make my function:

Example :: (a -> b) -> (b -> c) -> (c -> d) -> a -> d
Example f g h x = f ( g ( h (x) )

I'd really appreciate it, if you guys could help me clarify. Thank you!

I think that you already know the theory behind the type you're writing, so I'll try to inject some intuitive way to read it (at least I hope so, your question is not totally clear to me).

When you read something like (a -> b) inside a type, that's a function, as you said. For example (Int -> Bool) is a function.

Let's make an example:

even :: Int -> Bool -- A more generic version of that is in the Prelude
even n = n `rem` 2 == 0

filter :: (Int -> Bool) -> [Int] -> [Int] -- And of that, too
filter _ [] = []
filter f (x:xs)
    | f x       = x : filter f xs
    | otherwise = filter f xs

filteredEven :: [Int]
filteredEven = filter even [1..5] -- it gives [2, 4]

In this example we have a "high order function", a function that get another function and use it in some way.

In a function like the one you're defining you simply use 3 functions (and another parameter). But you can know more.

Each function you declare in the type accept a value returned from the previous one. So a possible solution is the one you have already showed. But the types are generic. There is not a total function that returns a generic value (where total means that it terminate always returning a value different from bottom if all the values are total and different by bottom, so it don't crash or return undefined, for example). So, if you wants a total function you have to have a way to generate the variables requested, from the context of the function (their parameters).

In the example before, using the names used by you, you have to return a value of type d. You only have a way to produce a value of that type, the h function. But to use the h function you have to get a value of type c. You only have the g function for that. But you need a value of type c. Fortunately you have the function f, that in exchange of a value of type a returns the value needed. We have this value (and don't have any other way to obtain a value of that type), so the function can be written. We can't in any way alter the values obtained (call multiple times the functions don't work, for purity and the fact that we have only a way to produce the values), so that's the only way to construct the function, if we wants it to be total:

Example (a -> b) -> (b -> c) -> (c -> d) -> a -> d
Example f g h x = h (g (f x)))

We can write the function in many other ways, but the results they give will be always the same (if Example, f, g and h are total and x is not bottom). So the type can express really well the function, because we can understand how the function works only looking at the type!

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