Search code examples
haskellpolymorphismquantifiers

List of polymorphic functions in haskell?


Consider the code below:

t1 :: [Int] -> (Int,String)
t1 xs = (sum xs,show $ length xs)

t2 :: [Int] -> (Int,String)
t2 xs = (length xs, (\x -> '?') <$> xs)

t3 :: [Int] -> (Char,String)
t3 (x:xs) = ('Y',"1+" ++ (show $ length xs))
t3  []     = ('N',"empty")

These three functions have a type that only varies partially -- they are entirely usable without needing to know the type of the first component of the tuple they produce. This means that I can operate on them without needing to refer to that type:

fnListToStrs vs fs = (\x -> snd $ x vs) <$> fs

Loading these definitions into GHCi, all three of the functions work independently as an argument to fnListToStrs, and indeed I can pass in a list containing both t1 and t2 because they have the same type:

*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]

But I can't pass all 3 at the same time, even though the divergence of types is actually irrelevant to the calculation performed:

*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]

I have the feeling that making this work has something to do with either existential or impredicative types, but neither extension has worked for me when using the type declaration I expect fnListToStrs to be able to take, namely:

fnListToStrs :: [Int] -> [forall a.[Int]->(a,String)] -> [String]

Is there some other way to make this work?


Solution

  • Existential is correct, not impredicative. And Haskell doesn't have existentials, except through an explicit wrapper...

    {-# LANGUAGE GADTs #-}
    
    data SomeFstRes x z where
      SFR :: (x -> (y,z)) -> SomeFstRes x z
    
    > fmap (\(SFR f) -> snd $ f [1,2]) [SFR t1, SFR t2, SFR t3]
    ["2","??","1+1"]
    

    but, this really is a bit useless. Since you can't possibly do anything with the first result anyway, it's more sensible to just throw it away immediately and put the remaining function in a simple monomorphic list:

    > fmap ($[1,2]) [snd . t1, snd . t2, snd . t3]
    ["2","??","1+1"]