While studying polyvariadic functions in Haskell I stumbled across the following SO questions:
How to create a polyvariadic haskell function?
Haskell, polyvariadic function and type inference
and thought I will give it a try by implementing a function which takes a variable number of strings and concatenates/merges them into a single string:
{-# LANGUAGE FlexibleInstances #-}
class MergeStrings r where
merge :: String -> r
instance MergeStrings String where
merge = id
instance (MergeStrings r) => MergeStrings (String -> r) where
merge acc = merge . (acc ++)
This works so far if I call merge with at least one string argument and if I provide the final type.
foo :: String
foo = merge "a" "b" "c"
Omitting the final type results in an error, i.e., compiling the following
bar = merge "a" "b" "c"
results in
test.hs:12:7: error:
• Ambiguous type variable ‘t0’ arising from a use of ‘merge’
prevents the constraint ‘(MergeStrings t0)’ from being solved.
Relevant bindings include bar :: t0 (bound at test.hs:12:1)
Probable fix: use a type annotation to specify what ‘t0’ should be.
These potential instances exist:
instance MergeStrings r => MergeStrings (String -> r)
-- Defined at test.hs:6:10
instance MergeStrings String -- Defined at test.hs:4:10
• In the expression: merge "a" "b" "c"
In an equation for ‘bar’: bar = merge "a" "b" "c"
|
12 | bar = merge "a" "b" "c"
|
The error message makes perfect sense since I could easily come up with, for example
bar :: String -> String
bar = merge "a" "b" "c"
baz = bar "d"
rendering bar
not into a single string but into a function which takes and returns one string.
Is there a way to tell Haskell that the result type must be of type String
? For example, Text.Printf.printf "hello world"
evaluates to type String
without explicitly defining.
merge a b c etc…
cannot be inferred, you want GHC to infer a type ofString
, otherwise use the inferred type. Is this interpretation correct? I can’t think of any way to do this, but I wouldn’t be able to conclusively say that it’s impossible either. – bradrnprintf
example only works becausePrintfType
has an instance forIO
; when testing in GHCi, any type which can be specialised toIO
will automatically be run. If I defineinstance (a ~ ()) => MergeStrings (IO a) where merge = putStrLn
,bar = merge "a" "b" "c"
works for me as well in GHCi. And, outside GHCi,printf "hello world"
results in an ambiguous type variable error, in exactly the same way thatbar = merge "a" "b" "c"
does. – bradrn