1

我正在Standrd ML 中为课堂作业编写凯撒密码。我对函数式编程非常熟悉,知道地图可能是我想要的。我无法理解在标准 ML 中实现地图功能的方式。

fun chrEnc (letter:char, key:int): char = 
    if Char.isAlpha(letter) then 
        if Char.isUpper(letter) then 
            chr (ord #"A" + (ord letter - ord #"A" - key) mod 26)
        else  chr (ord #"a" + (ord letter - ord #"z" - key) mod 26)
    else letter;

fun chrDec(letter:char, key:int): char  =
    chrEnc(letter,  (~1 * key));

fun msgEnc(message:string, key:int): string  =
    implode (map (fn x => chrEnc(x,key)) (explode message));

您可能会猜到 msgEnc 的预期行为是获取消息和键,并遍历消息,执行 chrEnc(x key) 其中 x 是字符串消息中的当前值并返回映射的字符串。msgEnc("IBM",1); 的预期输出 应该是“HAL”。但是,它是“HBM”,这使它看起来好像只对第一个字符进行操作。我想也许使用 (explode message) 作为 map 的列表参数可能是问题,所以我尝试了:

fun msgEnc(message:string, key:int): string  =
 val msg = explode message;
 implode (map (fn x => chrEnc(x,key)) msg);  

但是 val 上的 REPL barfs 说:

= = = = = [自动加载]
[库 $SMLNJ-BASIS/basis.cm 稳定]
[自动加载完成]
val chrEnc = fn : char * int -> char
- - = val chrDec = fn : char * int -> char
- - = stdIn:27.2 错误:在 VAL 处发现语法错误

不知道我错过了什么,我的假设是我误解了 map 的语法或用法。昨天之前我从未见过 ML,所以我是个傻子。

4

1 回答 1

1

首先,您的原始代码实际上似乎对我有用,所以也许可以尝试在新的 REPL 中重新编译或运行您的代码:

- msgEnc("IBM", 1);
val it = "HAL" : string

您的第二段代码的问题只是语法错误。你不能val在这样的函数范围内有简单的绑定,只能在顶层。对于函数的局部变量,请使用let

fun msgEnc (message:string, key:int) : string =
    let
       val msg = explode message
    in
       implode (map (fn x => chrEnc(x, key)) msg)
    end

这实际上完全等同于您的原始代码,因为唯一的区别是本地msg绑定。

标准 ML 非常面向表达式:函数体必须是单个表达式。您有两个语句,但val绑定不是语句。您可以使用分号和括号对表达式进行排序,但这仅对具有副作用的代码非常有用,例如:

let
    val name = "nick"
in
    (print "hi "; print name)
end

整个事情也是一个表达式,其中表达式的值是序列let中的最后一个表达式。(...; ...; ...)事实上,代码中的分号实际上都不是必需的。

希望有帮助!

于 2013-04-24T16:21:21.403 回答