Reputation: 887
I have written the following function at one time in the past, to replace any instance of an integer x in a list, with another integer y. Here's my code:
substitute::Int->Int->[Int]->[Int]
substitute x y [] =[]
substitute x y (z:zs)
|(z==x) =y:substitute x y (zs)
|otherwise =z:substitute x y (zs)
Here's a sample call:
main = do
print $ substitute 2 3 [2, 2, 2]
I now want to make this code work with any input type. So I tried converting the parameter types to a generic "a", but that spits out an error as Haskell thinks it is some sort of a customary higher-order function. So how can I make this work:
substitute::a->a->[a]->[a]
substitute x y [] =[]
substitute x y (z:zs)
|(z==x) =y:substitute x y (zs)
|otherwise =z:substitute x y (zs)
main = do
print $ substitute 2 'a' [2, 2, 2]
Upvotes: 0
Views: 108
Reputation: 11923
Haskell supports polymorphism, so functions like the one you require can be made. @Sibi 's response shows one method of finding it out, but doesn't explain why, so I'll show you why.
It's clear that your function has a type of a -> a -> [a] -> [a]
, as you indicated, but because you use the ==
function , which belongs to the Eq
typeclass, a constraint is applied: (Eq a) => a -> a -> [a] -> [a]
. Yes, this requires knowledge of Haskell typeclasses, but it's worth learning for times when you don't have GHCi with you.
Sometimes we can avoid using the Eq
typical in our function type by using pattern matching, but unfortunately, I don't see any current way of removing the ==
and substituting a pattern. Maybe in the future Haskell will support function patterns like plus a a = 2 * a
, but that's wishful thinking.
A useful sidenote in understanding polymorphic type signatures is that names like the above a
are called type variables. The way to differentiate them from concrete types is easy: they always start with a lowercase letter, whereas typeclass constructors start with a capital letter or :
for infix constructors, with the exception of the function infix constructor, ->
.
Upvotes: 0
Reputation: 48746
One way to find out is remove the type signature from your code and find it out using ghci:
λ> :t substitute
substitute :: Eq a => a -> a -> [a] -> [a]
Haskell has a good type inference, so it will automatically give the most polymorphic type for you.
substitute :: Eq a => a -> a -> [a] -> [a]
substitute x y [] =[]
substitute x y (z:zs)
|(z==x) =y:substitute x y (zs)
|otherwise =z:substitute x y (zs)
UPDATE: Just saw your updated question. Haskell doesn't have Heterogeneous list by default, so what you want cannot be done. But you can use Existential data type to get what you want. Read this section to understand more about it.
{-# LANGUAGE ExistentialQuantification #-}
data ShowBox = forall s. Show s => SB s
instance Show ShowBox where
show (SB s) = show s
substitute :: ShowBox -> ShowBox -> [ShowBox] -> [ShowBox]
substitute x y [] =[]
substitute (SB x) (SB y) ((SB z):zs)
|(show z == show x) = (SB y):substitute (SB x) (SB y) (zs)
|otherwise = (SB z):substitute (SB x) (SB y) (zs)
λ> substitute (SB 'a') (SB 3) [SB 1, SB 'a', SB 3]
[1,3,3]
Note that the above program is an anti pattern. Don't do that unless you have the right reasons.
Upvotes: 2