使用什么来代替列表理解
我刚刚开始使用 Haskell 并完成了一个很好的练习< /a> 制作凯撒密码。
第一步是创建一个函数,将字母转换为数字。我知道 chr 和 ord 已经可以做到这一点,但练习的一部分是编写您自己的。
let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c]
我是 Haskell 语法的新手,我学到的第一件事就是列表推导式,所以这已经成为我的锤子。不过我很好奇,编写这个函数的另一种(可能更好)方法是什么?
如果您好奇,密码的其余部分位于 gist 中。
编辑
我也对从数字翻译回字母的其他方法感兴趣。
num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)]
I'm just getting started with Haskell and finished a nice exercise to make a Caesar cipher.
One of the first steps was to make a function that will take a letter and turn it into a number. I know that chr and ord can do this already but part of the exercise was to write your own.
let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c]
I'm new to the Haskell syntax and one of the first things I learned was list comprehensions, so that has become my hammer. I'm very curious though, what is another (likely better) way to write this function?
If you're curious the rest of the cipher is in a gist.
EDIT
I'm also interested in other ways to translate back from numbers to letters.
num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我的解决方案:
或者:
或者在 毫无意义的风格中:
函数
elemIndex
返回给定列表中与查询元素相等(通过==
)的第一个元素的索引,如果没有这样的元素,则为Nothing
。Maybe
类型封装了一个可选值。Maybe a
类型的值要么包含a
类型的值(表示为Just a
),要么为空(表示为>什么都没有
)。使用Maybe
是处理错误或异常情况的好方法,而无需采取错误等严厉措施。函数
fromJust
从Just
中提取元素。My solution:
Or:
Or in pointless style:
The function
elemIndex
returns the index of the first element in the given list which is equal (by==
) to the query element, orNothing
if there is no such element.The
Maybe
type encapsulates an optional value. A value of typeMaybe a
either contains a value of typea
(represented asJust a
), or it is empty (represented asNothing
). UsingMaybe
is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.The function
fromJust
extracts the element out of aJust
.相反的过程:
!!
是一个 列表索引(下标)运算符,从0
开始。它是更通用的Data.List.genericIndex
的实例,它采用任何整数类型的索引。(!!)
在这里部分应用,这意味着它仍然需要一个Int
类型的参数来生成结果(列表中的一个值,其索引等于您传递给num2let
的Int
值)。The reverse process:
!!
is a List index (subscript) operator, starting from0
. It is an instance of the more generalData.List.genericIndex
, which takes an index of any integral type.(!!)
is partially applied here, which means it still needs one argument of typeInt
to yield the result (a value from the list whose index equals toInt
value you pass tonum2let
).“凯撒只是将消息中的每个字母替换为字母表中向下三个位置的字母,环绕在字母表的末尾。”我们可以简单地用 Haskell 编写它。事实上,我们可以完全避免
let2num
和num2let
。因此,让我们从定义一个表来将纯文本字母表映射到密文字母表开始:
它看起来像
现在我们可以加密一个符号,如果我们简单地在这个字典中
查找
字母:lookup
返回一个Maybe Char
值,我们需要将其转换为简单的Char
,为此我使用maybe
函数,使用'?'
表示在密码中未找到的符号,id
(身份函数=无更改)表示找到的符号:现在我们可以编写一个
加密< /code> 函数只对一个符号进行编码,它会留下缺失的字符,例如未加密的空格:
要加密整个字符串:
所以我们可以将它们放在一起:
“Caesar simply replaced each letter in the message by the letter three places further down the alphabet, wrapping around at the end of the alphabet.” We can simply write it in Haskell. In fact we can avoid
let2num
andnum2let
altogether.So let's start with defining a table to map plain text alphabet to the cipher text alphabet:
It will look like
Now we can encrypt a symbol, if we simply
lookup
the letter in this dictionary:lookup
returns aMaybe Char
value, we need to convert it to simply aChar
, and for this I usemaybe
function, using'?'
for symbols which were not found in the cipher, andid
(identity function = no changes) to found symbols:Now we can write an
encrypt
function to encode just one symbol, it will leave missing characters, like a space, unencrypted:To encrypt an entire string:
So we can put it all together:
为了完整起见,我认为有人应该提到列表推导式只是在列表单子中编写内容的快捷方式。您的代码转录大致如下:
这不是一个非常有趣的示例,但就是这样。
另外,对 do 语法进行脱糖处理,这是相同的:
For completeness, I think somebody should mention that list comprehensions are just a shortcut for writing stuff in the list monad. Your code transcribed is, roughly, this:
Not a very interesting example, but there you go.
Also, de-sugaring the do syntax, this is the same:
我不确定您为什么反对
ord
解决方案。基于列表的解决方案执行不必要的工作(遍历列表)。它们仍然被脱糖为调用enumFromTo
,这是Enum
类的一个方法,它允许在Int
和Char 之间进行转换
与ord
/chr
的方式相同。这是为Char
类型提供的最低级接口,因此您几乎无法在这里“编写自己的”(除了自己进行装箱/拆箱,但这并不是一个很大的乐趣)。I'm not sure why you are opposed to the
ord
solution. List-based solutions perform unnecessary work (traversing a list). And they still are desugared into invocation of theenumFromTo
, a method of theEnum
class which allows to convert betweenInt
s andChar
s in the same way asord
/chr
do. This is the lowest-level interface provided forChar
type, so you hardly can "write your own" here (apart from doing boxing/unboxing yourself, but this is not a big joy).我会使用以下内容:
并使用
n
所需的偏移量在字符串上进行map (caesar n)
。I would go with the following:
and
map (caesar n)
over the string withn
the desired offset.