Haskell摩尔斯电码练习 - 如何在列表项之间添加“空白”

时间:2017-10-09 20:22:31

标签: list haskell types syntax morse-code

我目前正在Haskell中使用摩尔斯电码编码器。这是我第一次在Haskell工作,我发现很难以“功能”的方式思考。到目前为止,我已经想出了这个:

module Formative1
    (encode, decode, toTree, toTable)
where

import safe Lib

encode :: String -> [MorseUnit]
encode str = codeText(words str)

codeWord :: String -> [MorseUnit]
codeWord word = map codeSymbol word

codeText :: [String] -> [MorseUnit]
codeText list = map codeWord list

解释我的代码: encode是主要功能。它使用words将句子分解为单词列表。 codeText用于将函数codeWord应用于列表中的每个单词。 codeWord然后maps覆盖每个字词中的每个字符,并使用MorseUnit找到codeSymbol

我对此解决方案有两个问题:

问题1:由于[MorseUnit]不匹配[[MorseUnit]],每次运行时都会收到错误,我相信这是因为我使用了map两次,所以它在一个列表。但是,如果不使用map,我就无法想到另一种解决方案。

问题2:摩尔斯电码规则规定,在每个字母之后,应该有一个“shortGap”,并且在每个字之后,应该有一个“mediumGap”。我不知道如何在列表的每个元素之间插入任何字符串(我会在map codeSymbol word中的每个元素之间插入shortGap,因此shortGaps位于每个字母之间,我会在{{1}中的每个元素之间插入mediumGap所以mediumGaps在每个单词之间)。我也不明白我会在什么时候添加差距,因为我不想意外地将map codeWord list应用于任何差距并替换它们。

任何解决方案都会有所帮助!谢谢。

2 个答案:

答案 0 :(得分:1)

第1期

错误是由两张地图引起的。但您也可以从类型签名中看到它:

codeText list = map codeWord list (where list :: [String])
codeWord :: String -> [MorseUnit]
map :: (a -> b) -> [a] -> [b]

如果您将(a -> b)替换为(String -> [MorseUnit]),则[a]变为[String][b]变为[[MorseUnit]]

与数学一样,有很多方法可以做到这一点。显然你只能concat得到的结果列表。请注意直截了当的[[a]] -> [a]签名。

请注意,之后会有concatMap。您可以使用它来代替map,这样会使结果变平。

为了进一步让您感到困惑,如果您发现参数在声明和定义中都显示在最后,您可以省略它:

codeText = concatMap codeWord

我建议您使用Hoogle搜索所需的功能签名。

第2期

首先,由于你需要区分单词和符号,在我看来你可能不需要这么早地压扁列表。我不熟悉莫尔斯电码,所以我不完全明白你想做什么。如果你能在类型和签名中表达你的概念,那就更清楚了。我的建议是查看intersperse :: a -> [a] -> [a]intercalate :: [a] -> [[a]] -> [a]以填补您的空白。需要使用import Data.List导入它们。

答案 1 :(得分:-1)

碰巧,你需要Monad。 Haskell有许多(我的意思是很多)Monad教程可以在线获得,我鼓励你利用其中的一个。

列表类型[]Monad类型类的实例。没有详细说明,这意味着有一个函数concatMap :: (a -> [b]) -> [a] -> [b]。从类型中,您可以推断它与map :: (a -> b) -> [a] -> [b]类似,但以某种方式展平(或concat s)list-of-list结构。

concatMap(>>=) :: Monad m => (a -> m b) -> m a -> m b,专门针对m ~ []

我们也可以忽略你的函数的参数,因为Haskell中的函数是curry。

encode :: String -> [MorseUnit]
encode = codeText . words

codeWord :: String -> [MorseUnit]
codeWord = map codeSymbol

codeText :: [String] -> [MorseUnit]
codeText = concatMap codeWord

关于第二个问题,请尝试使用intercalate。举个例子:

> intercalate ", " ["hello", "world"]
"hello, world"