在元组列表中找不到搜索值时出现“错误字符”

时间:2019-11-10 16:56:05

标签: haskell

在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 _ [] =  '#'
   |                   ^^^

我应该如何解决?

1 个答案:

答案 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