Reputation: 48664
I have the following piece of code:
{-# LANGUAGE OverloadedStrings #-}
import Data.List
import Data.Text hiding (foldl1', map)
gDatatoText :: Show a => [(a, a)] -> Text
gDatatoText xs = foldl1' append alltext
where conv (a,b) = append (t' a) $ append "\t" (append (t' b) "\n")
t' = numtoText
alltext = map conv xs
numtoText :: Show a => a -> Text
numtoText = pack . show
Now this works fine for the following input:
λ> let a = [(1,2)] :: [(Int,Int)]
λ> gDatatoText a
"1\t2\n"
Now I want it for work for inputs like this:
λ> let b = [(1,2)] :: [(Int,Double)]
λ> gDatatoText b
Now this throws error like this:
Couldn't match type `Double' with `Int'
Expected type: [(Int, Int)]
Actual type: [(Int, Double)]
Now my gut feeling says that this can be solved by RankNTypes
. But my attempts have failed. Any pointers on how to solve this ? Is this solvable using RankNTypes
?
Upvotes: 1
Views: 82
Reputation: 10783
The binding t'
restricts the type of numtoText
(due to the monomorphism restriction), so we start by getting rid of it and just using numtoText
directly.
conv (a,b) = append (numtoText a) $ append "\t" (append (numtoText b) "\n")
The other two options would be to give t'
an explicit type signature t' :: Show a -> Text
or to enable NoMonomorphismRestriction
. I would opt for getting rid of t'
altogether though.
Now, all we have to do is change your type signature for gDatatoText
:
gDatatoText :: (Show a, Show b) => [(a, b)] -> Text
Your previous type signature required that both elements of the tuples have the same type, but that isn't necessary. All that is necessary is that both of those types have a Show
instance.
Regarding RankNTypes
RankNTypes
is completely unrelated to this issue. RankNTypes
for when you need to nest a forall
inside of another type (such as a function type), as in (forall a. f a -> a) -> [Int] -> Int
which is an example of a rank-2 type. That type is different from forall a. (f a -> a) -> [Int] -> Int
. In the former case, the caller of the function (forall a. f a -> a)
gets to decide the type of a
, in the latter case the function gets to pick the type. The first example requires RankNTypes
, the second one does not (and is the same as just (f a -> a) -> [Int] -> Int
. forall
s at the top-level are implicit in Haskell).
The short of it is, RankNTypes
is for forall
s inside arguments passed to type constructors.
Upvotes: 7