haskelltypesfunctional-programminglogicdeclarative

haskell function type simplifyed f :: ((b -> a ) -> a -> c ) -> (b -> a ) -> b -> c


Just looking for an explanation of the type of this function, please

In functional programming this refers to the study of the type of returned values.

f x y z = x y (y z)

Prelude is the haskell interpreter which solves it as:

f :: ((b -> a) -> a -> c) -> (b -> a) -> b -> c

But I'm not able getting that result with any known method ¬¬

Best regards.


Solution

  • Ugh, those “manually typecheck this expression” exercises are so silly. I don't know why lecturers keep putting them in assignments.

    In practice, what's actually much more relevant is to go the other way around: given a type, find an implementation. So let me answer the question from that angle: you already know

    f :: ((b -> a) -> a -> c) -> (b -> a) -> b -> c
    --   └──────────────────┘    └──────┘   └─┘
    

    ...so you have three arguments to accept, reasonable enough to call them x, y and z

    f x y z = _
    

    You're in the end looking for a c, and the only c you have available is in the final result of x

        x :: (b -> a) -> a -> c
        --   └──────┘   └─┘
    

    ...which requires two arguments

    f x y z = x _ _
    

    ...of types b -> a and a. Let's check what we have available

        y :: b -> a
        z :: b
    

    Great, we can directly use y as the first argument

    f x y z = x y _
    

    For the second argument we need an a. Well, z is a b, that doesn't work, but y yields an a when given a b, so we can pass y z and thus end up with

    f x y z = x y (y z)
    

    or as we prefer to write it in Haskell, f x y = x y . y.

    Now for the other way around: let's start with the η-reduced form

    f x y = x y . y
    

    This is a pipeline, so let's start giving the passing-through argument a name p

            x y . y :: p -> _
    

    That argument is passed first to y, so we have

            y :: p -> _
    

    from which it follows, since y is also the first argument to x

            x :: (p -> _) -> _
    

    Furthermore, x then accepts (in the pipeline) whatever comes out of y

            y :: p -> r
            x :: (p -> r) -> r -> _
    

    Let's call the final result q

            y :: p -> r
            x :: (p -> r) -> r -> q
    

    And write up the whole function as given:

    (\x y -> x y . y) :: ((p -> r) -> r -> q) -> (p -> r) -> p -> q
    --                   └─────────x────────┘    └──y───┘
    

    Which is, after renaming the type variables, the same as what you started with.