Haskell 哈斯克尔不能';t将预期类型与实际类型匹配

Haskell 哈斯克尔不能';t将预期类型与实际类型匹配,haskell,Haskell,所以我试着用频率分析来破译密码 import Data.Char import Data.List import Data.Function import qualified Data.Map as DMap codedMsg = "V'Z GELVAT GB GRNPU GUR PNIRZRA GB CYNL FPENOOYR. VG'F HCUVYY JBEX. GUR BAYL JBEQ GURL XABJ VF 'HAU', NAQ GURL QBA'G XABJ UBJ GB

所以我试着用频率分析来破译密码

import Data.Char
import Data.List
import Data.Function
import qualified Data.Map as DMap

codedMsg    = "V'Z GELVAT GB GRNPU GUR PNIRZRA GB CYNL FPENOOYR. VG'F HCUVYY JBEX. GUR BAYL JBEQ GURL XABJ VF 'HAU', NAQ GURL QBA'G XABJ UBJ GB FCRYY VG."

mostFreqLtr = ["E", "T", "A", "O", "I", "N", "S", "H", "R", "D", "L", "C", "U", "M", "W", "F", "G", "Y", "P", "B", "V", "K", "X", "J", "Q", "Z"]

--weed out non alphabetical characters from the list
alphaSort lst
    | null lst              = []
    | isAlpha (head lst)    = (head lst) : alphaSort (tail lst)
    | otherwise             = alphaSort (tail lst)

--sort the list by characters
msgSort []  = []
msgSort lst = sortBy (compare `on` ord) lst

--group each character into it's own list
grp []  = []
grp lst = group lst

--sort the list into most frequent character first
lSort []    = []
lSort lst   = reverse (sortBy (compare `on` length) lst)

--change the list into one instance of each character
oneChar []  = []
oneChar lst = take 1 (head lst) : oneChar (tail lst)

--Pairing letters and creating a map of tuples containing frequency related characters
msg     = zip (oneChar $ lSort $ grp $ msgSort $ alphaSort $ map toUpper $ codedMsg) mostFreqLtr
msg2    = DMap.fromList msg

--replace coded list with analyzed list
replaceChars lst
    | null lst              = []
    | isAlpha (head lst)    = DMap.lookup (head lst) msg2 : replaceChars (tail lst)
    | otherwise             = (head lst) : replaceChars (tail lst)

result = replaceChars codedMsg
我不断地发现这个错误:

Couldn't match expected type `Char' with actual type `[Char]'
    Expected type: DMap.Map Char a0
      Actual type: DMap.Map [Char] [Char]
    In the second argument of `DMap.lookup', namely `msg2'
    In the first argument of `(:)', namely
      `DMap.lookup (head lst) msg2'

在所有顶级函数上写入类型签名。然后你会发现

oneChar :: [[a]] -> [[a]]
然而,从用途来看,我猜你是有意的

oneChar :: [[Char]] -> [Char]
您应该使用
head
,而不是
take 1
,或者您应该
concat
ed结果以获得
Char
s列表


实际上,您构建的map
msg2
[Char]
作为键,但您尝试使用它,就像它将
Char
s作为键一样。

嗯-我坐下来思考了一下您的代码

  • 请使用类型签名,这有助于思考您的代码,而且编译器也可以进行优化

  • 给出更有意义的名字

    • mostFreqLtr
      ->
      frektable\u EN
      (它清楚地表明您正在破译英文文本)
    • alphaSort
      ->
      filterAlpha
      (这是一种误导,因为您过滤的是非字母元素,而没有对任何内容进行排序
    • msgSort
      ->
      sort
      (我认为是一样的)
  • 使用模式匹配,而不是
    头部
    尾部

    i、 e.lst…头部lst…尾部lst->
    lst@(c:cs)
    • 然后,lst被称为它自己,
      c
      是它的头,
      cs
      是它的尾(单个元素通常被称为单个字母,列表作为它们的准字母,并附加s
代码: 只导入必要的代码位

codedMsg :: String
codedMsg    = "V'Z GELVAT GB GRNPU GUR PNIRZRA GB CYNL FPENOOYR." ++ 
              "VG'F HCUVYY JBEX. GUR BAYL JBEQ GURL XABJ VF 'HAU'," ++
              "NAQ GURL QBA'G XABJ UBJ GB FCRYY VG."

freqTable_EN :: [Char]
freqTable_EN = ['E', 'T', 'A', 'O', 'I', 'N', 'S', 'H', 'R'] ++
               ['D', 'L', 'C', 'U', 'M', 'W', 'F', 'G', 'Y'] ++
               ['P', 'B', 'V', 'K', 'X', 'J', 'Q', 'Z']
不要使用太长的行-这会降低代码的可读性,姓氏
frektable_EN
非常不寻常,但在这种情况下,我可以随意偏离标准,因为它可读性更好。我还使用
[Char]
而不是
String
(相当于)来更清楚地说明它是一个字母表

-- weed out non alphabetical characters from the list
filterAlpha :: String -> String
filterAlpha = filter isAlpha

-- sort a list by length
sortByLength :: [[a]] -> [[a]]
sortByLength = sortBy (compare `on` length)

-- sort the list into most frequent character first
sortByFreq :: [[a]] -> [[a]]
sortByFreq = reverse . sortByLength
对于好的函数名,这样的注释是不必要的

-- change the list into one instance of each character
reduceGroups :: [[a]] -> [a]
reduceGroups lst = map head lst
您还可以保留
lst
这件事,因为编译器足够聪明,可以从类型签名中获取所有信息,所以最后一行也可以是
reduceGroups=map head

-- Pairing coded message with frequency table
pairs :: [(Char, Char)]
pairs = nonAlphaPairs ++ zip freqSortedMsg freqTable_EN
  where cleanedMsg    = (filterAlpha . map toUpper) codedMsg
        freqSortedMsg = (reduceGroups . sortByFreq . group . sort) cleanedMsg
        nonAlphaPairs = map (\x ->(x,x)) $ filter (not . isAlpha) codedMsg
(\x->(x,x))
是一个lambda表达式,它只是在一对字符中转换一个字符,因为它们被自己解码

-- and creating a map for decryption
cipher :: Map Char Char
cipher = fromList pairs

-- replace encoded text by our cipher
decipher :: String -> String
decipher = mapMaybe (uplook cipher)
         where uplook = flip lookup

result :: String
result = decipher codedMsg

main :: IO ()
main = print result
最后一行打印您的结果-因为我们想阅读消息;-) 请随意询问是否有不清楚的地方

注:我真的很喜欢你的编码信息——尽管频率分析没有发现一个字母。我只是猜测了你的加密算法。(
g?
适用于vim用户),
我认为你必须使用更长的文本。

我必须纠正我自己频率分析发现了一个字母-它是
V
;在我在维基百科关于频率分析的文章中找到的较长文本中,有C、E、I、W、X被正确找到。
-- and creating a map for decryption
cipher :: Map Char Char
cipher = fromList pairs

-- replace encoded text by our cipher
decipher :: String -> String
decipher = mapMaybe (uplook cipher)
         where uplook = flip lookup

result :: String
result = decipher codedMsg

main :: IO ()
main = print result