Haskell - 凯撒密码 - 非穷举模式

时间:2016-05-29 00:42:12

标签: list haskell recursion

执行以下代码会导致非穷举模式错误。我无法弄明白为什么。请帮忙。感谢。

module Cipher where

import Data.Char

caesar :: Int -> [Char] -> [Char]
caesar n [] = []
caesar n st = go n st
   where go nn (x:xs)
          | (x:xs) == [] = []
          | ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
          | ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
          | otherwise = error "input error"

2 个答案:

答案 0 :(得分:3)

我认为错误在于以下几行

 where go nn (x:xs)
          | (x:xs) == [] = []

匹配(x:xs) == []永远不会成立,因为第一个总是一个带有(真实)头部和(可能是空的)尾部的列表

你可以通过

解决这个问题
 where go _ [] = []
       go nn (x:xs) | ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
                    | ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
                    | otherwise = error "input error"

虽然这种风格非常难以辨认 - 我建议从(+nn) $ ord x更改为ord x + nn以及chr (ord x + nn)

此外,你没有考虑

  • 转换中的空白以及
  • 标点符号,
  • 负数和
  • 大写字母!

由于这似乎是一项家庭作业/练习,我不会给出惯用的解决方案,但只提示有一个名为map的函数,你一定要查找并使用它!

您的函数go也不是必需的,您可以在没有它的情况下完全编写算法:

caesar :: Int -> String -> String
caesar _ [] = []
caesar n (x:xs)
          | 122 < ord x + n                    = chr (96 + n)    : caesar n xs
          | 97 <= ord x + n && ord x + n <=122 = chr (ord x + n) : caesar n xs
          | otherwise = error "input error"

请用&#34; Alea,iacta esto进行测试!&#34;而不是&#34; foo&#34; - 您将在第一个测试用例中找到更多错误。

更新

解决问题的惯用方法,你有一个列表并使用函数转换每个元素正在使用map,例如

> map (\x -> x + 3) [1..3]
[4,5,6]

因此你需要一个功能

cipher :: Int -> Char -> Char
cipher n x
    | isDigit x = chr $ ord '0' + (ord x - ord '0' + n'') `mod` 10
    | isLower x = chr $ ord 'a' + (ord x - ord 'a' + n' ) `mod` 26
    | isUpper x = chr $ ord 'A' + (ord x - ord 'A' + n' ) `mod` 26
    | otherwise = x
    where n'  = n `mod` 26 -- for the letters
          n'' = n `mod` 10 -- for the digits

caesar :: Int -> String -> String
caesar n xs = map (cipher n) xs

答案 1 :(得分:1)

您的go函数没有与空列表匹配的案例。 otherwise后卫在这里没有帮助,因为模式go nn (x:xs)与之匹配并不匹配。

试试这个:

caesar :: Int -> [Char] -> [Char]
caesar n [] = []
caesar n st = go n st
   where go nn (x:xs)
          | (x:xs) == [] = []
          | ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
          | ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
          | otherwise = error "input error"
         go _ _ = error "fix me"