我正在解决旧考试来练习SML。我发现一个有趣的任务是:编写一个函数repeat
,用签名'a - >执行另一个函数。 “一个。
我假设所请求的功能是咖喱功能,并使用o
- 运营商:
fun repeat (1, f: 'a->'a) = f
| repeat (n, f: 'a->'a) = f o repeat (n-1, f);
但是,o
运算符在正确的过程中没有正式引入,我想知道如果没有它我怎么写呢?
答案 0 :(得分:3)
不是那么冗长,而是以某种方式,最明确的,然后是更简洁的解释。
curried函数是获取单个参数的函数。如果表达式具有更多参数,则存在尽可能多的嵌套函数。第一个外层函数得到一个参数,它由一个内层函数组成,它可以由一个内部函数组成,依此类推。可以返回任何这种内部级别函数,而不仅仅是最内部函数,如后面所述(这是一种“部分评估”)。内部函数是“专门的”与外部函数的参数(形式上,参数绑定在一个闭包中)。
我们知道至少有一个函数参数f
和整数参数counter
。还需要有一个参数seed
,以便第一次调用函数f
。
嵌套的顺序可以是任意的或指定的。如果没有指定,我个人更喜欢将最不同的参数放在外部范围内,而在内部范围内变化最大。在这里,我要说的是,至少从变化到最大变化:f
,counter
seed
。
这足以建议模板的开头:
val repeat: ('a -> 'a) -> int -> 'a -> 'a =
fn f: 'a -> 'a =>
fn count: int =>
fn seed: 'a =>
…
我们已经实施了签名的('a -> 'a) -> int -> 'a
部分。仍然是最后一个-> 'a
,这意味着要返回'a
,它将由内循环进行评估。
循环可能是这种形式(伪代码):
val rec loop = fn i =>
if condition-to-stop
then return-something-or-`()`
else loop (i + 1) or (i - 1)
如果循环要计算某些东西,它将需要一个额外的参数作为累加器,并将该累加器作为其最终结果返回。
实现循环并将其放在上面的curried函数模板中,我们得到:
val repeat: ('a -> 'a) -> int -> 'a -> 'a =
fn f: 'a -> 'a =>
fn count: int =>
fn seed: 'a =>
let
val rec loop = fn (counter, x) =>
if counter <= 0 then x
else loop (counter - 1, f x)
in
loop (count, seed)
end
您了解let … in … end
构造吗?
注意counter
上的守卫可能会像你一样使用模式,但由于SML的整数可能是负数(SML中没有严格的自然),因此捕获这种情况也更安全,因此{{1而不是模式匹配。里程可能会有所不同,但这不是问题的重点。
与上述相同,使用if … then … else
代替fun
:
val rec
fun repeat (f: 'a -> 'a) (count: int) (seed: 'a): 'a =
let
fun loop (counter, x) =
if counter <= 0 then x
else loop (counter - 1, f x)
in
loop (count, seed)
end
注意事项参数不是由repeat
分隔的(两者都不是,
)。这是使用*
编写curried函数的方法(相反,fun
不是curry)。将它与同一函数的先前loop
版本进行比较。如果没有指定类型且只有名称,则可以省略括号。
用作val
参数的测试函数:
f
测试:
val appendAnX = fn s: string => s ^ "x"
Curried函数比获取元组的函数更抽象(这是一个正式的单个参数,因此也是一个curry函数,但这是另一个故事,有点作弊),因为外部函数可以部分应用:
这是部分申请,留下最后一个参数val () = print (repeat appendAnX 5 "Blah:")
,未绑定:
seed
然后可以应用此功能仅指定此val repeatAppendAnXThreeTimes = repeat appendAnX 3
:
seed
同样,val () = print (repeatAppendAnXThreeTimes "Blah:")
和counter
都可以免费使用:
seed
定义val repeatAppendAnX = repeat appendAnX
val () = print (repeatAppendAnX 4 "Blah:")
的另一种方式。将其与上面的其他定义进行比较:
repeatAppendAnXThreeTimes