Transforming functions of type `a -> b` into those of type `String -> String` in Haskell
functional-programming, haskell
Solution
Your code won't work because Haskell doesn't re-use or scope type variables; the `a` in `wrap :: (Read a, Show b) => (a -> b) -> (String -> String)` is a completely different `a` from the one in `read s :: a` (and they're both universally quantified). This is the source of the `a1` in the error message; GHC is alpha-converting the program to
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a1)
However, `f`'s argument type is fixed inside `wrap`, so simply removing the type annotation works fine. Your function becomes
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s)
-- Or wrap f = show . f . read
And you can use it:
ghci> map ($ "42") [wrap (+ (7 :: Integer)), wrap (* (2.0 :: Double))]
["49","84.0"]
Note that this means that `read s` has a type you can't write down. In Haskell 2010 (or 98), the only way to get around this is to use a function like `asTypeOf :: a -> a -> a`; `asTypeOf` is just `const`, but thanks to its type signature, it constrains its first, returned, argument to be of the same type as its second. Then, of course, you'd have to conjure up a variable of type `a`. The following would work for that:
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s `asTypeOf` fInput)
where fInput = undefined
fOutput = f fInput -- I still can't give this a type signature
In GHC, to avoid this, you can turn on the `ScopedTypeVariables` extension; with that on, if you explicitly qualify all your type variables with a `forall`, they'll be scoped just like value-level names. Then your code would become
{-# LANGUAGE ScopedTypeVariables #-}
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)
But remember, you don't need any type annotations at all for this simple example.
Problem
My intention is simple. I want to wrap functions of type `a -> b` into `String -> String` (so that a bunch of heterogeneous functions can be put in a list). So I write: ``` wrap :: (Read a, Show b) => (a -> b) -> (String -> String) wrap f = \s -> show $ f (read s :: a) ``` However, `ghc` complaints: ``` Could not deduce (Read a1) arising from a use of `read' from the context (Read a, Show b) bound by the type signature for wrap :: (Read a, Show b) => (a -> b) -> String -> String ``` I want to know why my piece of code won't work and what kind of hacks is needed to achieve my goal? Thanks.