Reputation: 91
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
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