Sibi
Sibi

Reputation: 48664

Text and Polymorphism

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

Answers (1)

David Young
David Young

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. foralls at the top-level are implicit in Haskell).

The short of it is, RankNTypes is for foralls inside arguments passed to type constructors.

Upvotes: 7

Related Questions