如何更改此函数以使用任何类型,而不仅仅是Int

时间:2014-12-02 06:10:33

标签: haskell

我过去曾一次写过以下函数,用另一个整数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]

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} }。