在Haskell作业中,我的任务是创建一个接受Char和元组对列表的递归函数。
我想扫描元组的第一个元素,如果它与输入'char'相匹配,则返回元组的第二个元素。
如果没有匹配项,则应返回'#'
到目前为止,这是我的代码:
find_pair :: (Eq a) => a -> [(a,b)] -> b
find_pair _ [] = error "#"
find_pair x ((a,b):xs) = if x == a then b else find_pair x xs
它应该像这样工作:
find_pair 'b' [('b', 'g'), ('c', 'h'), ('a', 'f')] = 'g'
find_pair '!' [('b', 'g'), ('c', 'h'), ('a', 'f')] = '#'
它几乎可以正常工作,但是我的老师不接受它,因为在函数的“#”部分返回:
*** Exception: #
CallStack (from HasCallStack):
error, called at haskell.hs:19:19 in main:Main
而不是'#'
但是,如果我这样写我的函数:
find_pair :: (Eq a) => a -> [(a,b)] -> b
find_pair _ [] = '#'
find_pair x ((a,b):xs) = if x == a then b else find_pair x xs
它甚至没有编译,并给我这个错误:
haskell.hs:19:19: error:
* Couldn't match expected type `b' with actual type `Char'
`b' is a rigid type variable bound by
the type signature for:
find_pair :: forall a b. Eq a => a -> [(a, b)] -> b
at haskell.hs:18:1-41
* In the expression: '#'
In an equation for `find_pair': find_pair _ [] = '#'
* Relevant bindings include
find_pair :: a -> [(a, b)] -> b (bound at haskell.hs:19:1)
|
19 | find_pair _ [] = '#'
| ^^^
我应该如何解决?
答案 0 :(得分:3)
您说要返回一个字符,但是类型签名指定了通用的返回类型b
,它不一定是字符。泛型类型意味着“无论您给我什么类型,我都可以使用它”-重点是您不选择该类型,但调用函数的人可以选择。
因此,如果您真的想返回特殊字符,则您的类型签名必须这样说:
find_pair :: (Eq a) => a -> [(a, Char)] -> Char
find_pair _ [] = '#'
find_pair x ((a,b):xs) = if x == a then b else find_pair x xs
但是,返回特殊值以指示特殊结果是脆弱的。如果您的输入实际上恰好包含字符'#'
怎么办?消费者如何分辨您是否找到了字符'#'
或什么都没找到?
当一个函数可能有结果也可能没有结果时,在Haskell中执行此操作的标准方法是返回包装在Maybe
中的值:
find_pair :: (Eq a) => a -> [(a,b)] -> Maybe b
find_pair _ [] = Nothing
find_pair x ((a,b):xs) = if x == a then Just b else find_pair x xs
在此,该函数在找到元素时将返回Just b
,在找不到元素时将返回Nothing
。