我必须写一个移位函数,从一个 "表"(列表)中搜索一个元素的对。如果元素不在给定的列表中,它必须给出一个'#'az的结果。
举例说明。
shift [('b', 'g'), ('c', 'h'), ('a', 'f')] 'a' == 'f'
shift [('b', 'g'), ('c', 'h'), ('a', 'f')] 'b' == 'g'
shift [('b', 'g'), ('c', 'h'), ('a', 'f')] 'b' == 'g'
shift [('b', 'g'), ('c', 'h'), ('a', 'f')] 'x' == '#'
我的代码:
shift :: [(Char,Char)] -> Char -> Char
shift z c = [b |(a,b)<-z,a==c]!!0
它能用,但异常情况就不行了。我似乎不能让它对不在列表中的元素起作用。我已经尝试过了。
shift z c
| c `elem` z =[b |(a,b)<-z,a==c]!!0
| otherwise ='#'
和一个辅助函数
isgood z c
| c `elem` z = (shift z c)
| otherwise = '#'
但都没有用 如何解决这个问题?
你可以有很多方法来写这个,基本上都是做同样的事情。
其中一种方法只是对你之前的一个尝试稍加修改,也就是 "可行,但例外情况下不行 "的方法。
shift :: [(Char,Char)] -> Char -> Char
shift z c = [b |(a,b)<-z,a==c]!!0
唯一的问题是,我相信你已经观察到了 当你找不到字符时,程序就会崩溃,而不是像你所希望的那样,函数给你 "#"。这是因为 (!! 0)
譬如 head
相当于),当应用于一个空列表时,会出现一个丑陋的运行时错误。所以你需要做的就是检查列表是否为空,然后取第一个元素或者给出默认答案。在我看来,最整洁的方法是在模式匹配中使用 case
表达式。
shift :: [(Char,Char)] -> Char -> Char
shift z c = case [b |(a,b)<-z,a==c] of
[] -> '#'
(c:_) -> c
但这种在 "查找表 "中以对子列表的形式查找东西的概念是如此标准,以至于Haskell Prelude已经有了一个函数,自然叫做: 查找. 它返回一个 Maybe
类型作为处理失败的安全方式,如果你想的话,你可以用类似于上一版本的方式对结果进行模式化匹配。
shift z c = case (lookup c z) of
Nothing -> '#'
Just c -> c
如果你愿意的话,你可以用类似于上一个版本的方法来进行模式匹配: 从可能,另一个标准库函数。
shift z c = fromMaybe '#' (lookup c z)
还有两点需要补充:
shift
这个函数的名字很奇怪,因为它需要一个任意对的查找表。对于真正的凯撒移位密码来说,这个表是隐含在移位数中的,你需要一个类型为 Int -> Char -> Char
这将是相当不同的执行方式。