Reputation: 2277
Here is my function
data Item a = One a | Many [Item a]
let flat (One x) = show x
let flat (Many xs) = show xs
Here is the output
Prelude> flat [[3]]
<interactive>:21:6:
Couldn't match expected type ‘Item t0’ with actual type ‘[[t1]]’
In the first argument of ‘flat’, namely ‘[[3]]’
In the expression: flat [[3]]
In an equation for ‘it’: it = flat [[3]]
It seems like flat doesn't recognize Item as its function signature so I tried redefine the function signature
flat :: Item a -> [a]
<interactive>:22:1:
Couldn't match type ‘a1’ with ‘Char’
‘a1’ is a rigid type variable bound by
an expression type signature: Item a1 -> [a1] at <interactive>:22:1
Expected type: Item a1 -> [a1]
Actual type: Item a1 -> String
In the expression: flat :: Item a -> [a]
In an equation for ‘it’: it = flat :: Item a -> [a]
But Haskell does not let you redefine function signature in ghci, is there a way around this?
Upvotes: 1
Views: 406
Reputation: 12123
Answering a follow-up question you asked in the comments of @jtobin's answer: yes there is a way to automatically dectect that [3]
needs to be wrapped into a Maybe constructor. However you'll probably need to add type annotations (cf. example
to help Haskell figure out what to do=.
We start with a bunch of language extensions.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
Then comes your definition of Item
.
module Item where
data Item a = One a | Many [Item a]
We introduce a class of things which may be reified to an Item a
and declare two instances: the Many
one and the base case. You can see that we now have overlapping instances (e.g. for Itemable [Int] [Int]) so you're playing with fire here.
class Itemable b a where
item :: b -> Item a
instance Itemable b a => Itemable [b] a where
item = Many . fmap item
instance Itemable a a where
item = One
You can finally define flat
as a function that turns a b
into an Item a
first and then flattens it:
flat :: Itemable b a => b -> [a]
flat = go . item where
go (One a) = [a]
go (Many as) = concatMap go as
Which works as the following example typechecking and evaluating to [2,43,7,8,1]
shows:
example :: [Int]
example = flat [[[[[[2::Int],[43]],[[7],[8]],[[1]]]]]]
However, as soon as you try to use the overlapping instances it'll blow in your face. E.g.:
example' :: [[Int]]
example' = flat [[[[[[2::Int],[43]],[[7],[8]],[[1]]]]]]
Upvotes: 1
Reputation: 3273
flat [[3]]
yields a type error. [[3]]
has type Num a => [[a]]
, not Show a => Item a
that you can pass into flat
.
flat (Many [3])
will return "[3]"
.
Upvotes: 4