我正在开始使用Haskell,但是我试图制作的这种相等检查并没有成功。
我有一个函数countLetter a [b] c
,其中a
是char,b
是字符列表,c
是int。 (类型声明通过罚款。)但是我遇到了这个表达式的问题:
if a == head(b)
给我以下信息:
Type error in application
*** Expression : a == head b
*** Term : a
*** Type : [a]
*** Does not match : a
*** Because : unification would give infinite type
如果需要,我的代码是完整的:
countLetter :: char -> [char] -> int
countLetter a [b] c = if null b
then []
else
if a == head(b)
then countLetter a tail(b) c+1
else
countLetter head(b) tail(b) c
非常感谢任何帮助或建议。谢谢。
答案 0 :(得分:9)
首先,Haskell中的类型以大写字母开头。如果在类型签名中使用以小写字母开头的标识符,则将它们解释为类型变量。因此,您的类型char -> [char] -> int
与a -> [a] -> b
相同,这对您的函数来说不是一个明智的类型。您想要Char -> [Char] -> Int
。
其次[]
不是Int
类型的有效值。修复您的类型签名应该会产生一条错误消息,告诉您更不明确的条款。
然后它还应该告诉您null b
是类型错误,因为b
的类型为Char
(函数的第二个参数类型为[Char]
而您已经将它与模式[b]
匹配,将b
绑定到该列表中包含的单个Char
,并且null
将列表而不是Char作为其参数。
稍微澄清最后一点:
你的函数的第二个参数是一个列表。通过在参数列表中编写[b]
,您可以将该参数与模式[b]
进行匹配。换句话说,写countLetter a [b] c = blabla
与写作相同:
countLetter a theList c =
case theList of
[b] -> blabla
所以你说:“函数的第二个参数必须是一个包含一个元素的列表,该元素应该被称为b
”。这不是你想要说的。你想要说的是“函数的第二个参数(顺便提一下,它是一个列表)应该被称为b
”。为此,您只需编写countLetter a b c = blabla
。
类型列表的参数不必与其他类型的参数进行任何不同的表示。
答案 1 :(得分:2)
您将遇到的另一个错误是:
countLetter head(b) tail(b) c
根据规则,这与
相同countLetter head b tail b c
即。你用count参数调用你的countLetter函数,只需要3个(根据第一个等式)或2个(根据你的类型签名)。 (这是编译器非常不满意的另一点。)
你可能想要这个:
countLetter (head b) (tail b) c
同样地:
countLetter a tail(b) c+1
与
相同(countLetter a tail b c) + 1
但你可能想要:
countLetter a (tail b) (c+1)
答案 2 :(得分:1)
除了提供修复功能的其他答案之外,您可能还需要考虑以更具成分的方式编写它。具体来说,通过构建其他标准函数来寻找编写函数的方法。假设您有一个函数将删除列表中不等于测试字母的所有内容。
myFilter :: Char -> [Char] -> [Char
myFilter = ...
使用myFilter
后,您将看到一个列表,其中只包含您要检查的元素。此时,您可以使用length
来获取列表的长度:
countLetter :: Char -> [Char] -> Int
countLetter a b = length $ myFilter a b
所以现在你只需要定义myFilter
,这可以使用标准Prelude函数filter
myFilter a b = filter (==a) b
对于一个小的函数,创建我们自己的定义几乎不值得,因为你可以写
countLetter a b = length $ filter (== a) b
现在,在ghci中定义它以查看它为函数countLetter
Prelude> let countLetter a b = length $ filter (== a) b
Prelude> :t countLetter
countLetter :: Eq a => a -> [a] -> Int
看不到Char
!实现不依赖于元素是字母,只是可以比较它们的相等性(这也适用于您的方法)。所以ghci在计算的类型中反映出来。但您可以通过将Char
替换为a
来确定这正是您想要的类型。
许多功能程序员倾向于找到这种方法,即通过组合较小的部件来构建功能,特别容易推理,因此它很常见。特别是在使用列表时,您可能希望查看是否可以使用所谓的高阶函数编写实现,例如map
,filter
或折叠,而不是使用递归。有时递归是最清晰的方式,但我希望你经常会发现函数组合是一种更好的方法。