PatchingMatching
PatchingMatching

Reputation: 91

Partially appplied function with (.) seems to take too few arguments

So, we have three functions:

A :: [([String], [String])] -> [String] -> [String]
A = B . C "*" f

B :: (a -> Maybe a) -> a -> a
C :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]

The thing that confuses me about this is that A takes two arguments, and those arguments will then be the arguments to C when A is called. Then the result of C will be the argument(s) to B, but how is that possible since B is supposed to take two arguments, when C like every other function I've seen so far in Haskell will just return one value.

From what I can gather from the dot operator:

(.) f g = \x -> f (g x)

Using the dot in A allows it to be this "point free" style, and makes it more readable. But what it says is:

A x y = B (C "*" f x y)

But I'm obviously missing something, since if I write it like that then:

* Couldn't match expected type `a0 -> Maybe a0'
              with actual type `Maybe [[Char]]'

And then I'm stumped.

Upvotes: 1

Views: 68

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476729

Using the dot in A allows it to be this "point free" style, and makes it more readable. But what it says is:

A x y = B (C "*" f x y)

What it says is:

 A x = B (C "*" f x)

since B has type B :: (a -> Maybe a) -> a -> a, it will return a function, and thus we can add an extra parameter:

A x y = B (C "*" f x) y

but these are different. Note that the (.) makes a chain for one parameter.

After all (.) is implemented like you say as:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

So here B is the left function, and (C "*" f) is the right function. So that means that (.) B (C "*" f) is equivalent to:

(.) B (C "*" f) x = B (C "*" f x)

If we analyze the types, we see:

(.)    :: (b             ->    c   ) -> ((a -> b) -> (a -> c))
B      :: (d -> Maybe d) -> (d -> d)
--------------------------------------------------------------
b ~ (d -> Maybe d), c ~ (d -> d)

so that means the type of (.) B is (a -> (d -> Maybe d)) -> (a -> (d -> d)), or less verbose (a -> d -> Maybe d) -> a -> d -> d.

Now we can analyze the type of C "*" f:

C   :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]
"*" ::       String
f   ::              ([a] -> [a])
--------------------------------------------------------------------
a ~ String

We do not know what f is here, but we will assume that it is a [String] -> [String] function, so the matching works.

This thus means that C "*" f has type [([String], [String])] -> [String] -> Maybe [String].

Now the types match, since:

(.) B   ::  (          a ->                d ->    Maybe d       ) -> a -> d -> d
C "*" f ::   [([String], [String])] -> [String] -> Maybe [String]
---------------------------------------------------------------------------------
a ~ [([String], [String])], d ~ [String]

So this means that (.) B (C "*" f) has type [([String], [String])] -> String -> String. This indeed holds if we determine this with ghci:

Prelude> :{
Prelude| b :: (a -> Maybe a) -> a -> a
Prelude| b = undefined
Prelude| :}
Prelude> :{
Prelude| c :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]
Prelude| c = undefined
Prelude| :}
Prelude> :t b . c "*" undefined
b . c "*" undefined
  :: [([[Char]], [[Char]])] -> [[Char]] -> [[Char]]

Upvotes: 1

Related Questions