我过去曾一次写过以下函数,用另一个整数y替换列表中整数x的任何实例。这是我的代码:
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)
以下是一个示例电话:
main = do
print $ substitute 2 3 [2, 2, 2]
我现在想让这个代码适用于任何输入类型。所以我尝试将参数类型转换为通用的“a”,但是由于Haskell认为它是某种习惯的高阶函数,因此会发出错误。那么我怎样才能做到这一点:
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]
答案 0 :(得分:2)
找到的一种方法是从代码中删除类型签名并使用ghci找到它:
λ> :t substitute
substitute :: Eq a => a -> a -> [a] -> [a]
Haskell有一个很好的类型推断,所以它会自动为你提供最多样的类型。
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)
更新:刚看到您更新的问题。默认情况下,Haskell没有异类列表,因此无法完成所需的操作。但您可以使用存在数据类型来获得所需内容。阅读this section以了解更多信息。
{-# 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]
请注意,上述程序是反模式。除非你有正确的理由,否则不要这样做。
答案 1 :(得分:0)
Haskell支持多态,因此可以创建所需的函数。 @Sibi的回复显示了找到它的一种方法,但没有解释原因,所以我会告诉你原因。
很明显,您的函数的类型为a -> a -> [a] -> [a]
,如您所示,但是因为您使用属于==
类型类的Eq
函数,约束已应用:(Eq a) => a -> a -> [a] -> [a]
。是的,这需要Haskell类型类的知识,但是当你没有GHCi时,它值得学习。
有时我们可以通过使用模式匹配来避免在函数类型中使用典型的Eq
,但不幸的是,我没有看到任何当前删除==
并替换模式的方法。也许将来Haskell会支持像plus a a = 2 * a
这样的功能模式,但这是一厢情愿的想法。
理解多态类型签名的一个有用的旁注是,像上面a
这样的名称被称为类型变量。将它们与具体类型区分开来的方法很简单:它们总是以小写字母开头,而类型类构造函数以大写字母或:
开头,用于中缀构造函数,函数中缀构造函数除外{{1} }。