【问题标题】:Achieving laziness and memoization实现懒惰和记忆
【发布时间】:2020-05-04 10:18:53
【问题描述】:

懒惰是Purely Functional Data Structures 一书中的基石,但没有清楚地描述他是如何获得它的,至少对我来说是这样。 我以为我只需要写:

datatype 'a susp = $ of 'a
fun force ($x) = x
fun plus (x, y) = $case (x, y) of ($m, $n) => m + n

然后我得到错误:

- use "ch4.sml";;
[opening ch4.sml]
ch4.sml:3.20 Error: syntax error: inserting  ORELSE
[unexpected exception: Compile]

uncaught exception Compile [Compile: "syntax error"]
raised at: ../compiler/Parse/main/smlfile.sml:19.24-19.46
../compiler/TopLevel/interact/evalloop.sml:45.54
../compiler/TopLevel/interact/evalloop.sml:306.20-306.23
../compiler/TopLevel/interact/interact.sml:65.13-65.16

我尝试将函数修改为

fun plus (x, y) = $(print "Evaluating...\n"; force x + force y)

但是用plus ($4, $5) 调用它会评估它并且没有记住它,因为它返回$ 9 而不是$ plus(force $4, force $5) 并且两次都打印Evaluating...

- plus ($4, $5);;
Evaluating...
val it = $ 9 : int susp
- plus ($4, $5);;
Evaluating...
val it = $ 9 : int susp

我也想获取关键字lazy,但我不确定 SML New Jersey 是否支持这个,它是由 Chris Okasaki 实现的,还是手动脱糖的。 关键字在我的编辑器中突出显示,但在编写时

fun lazy plus ($x, $y) = $ (x + y)

我知道lazy 是采用两个参数plus($x, $y) 的函数,由类型给出:

val lazy = fn : 'a -> int susp * int susp -> int susp


我的问题归结为如何在 SML New Jersey 中获得惰性和记忆力?

【问题讨论】:

    标签: functional-programming sml smlnj


    【解决方案1】:

    你需要开启惰性并添加一些括号(书中的$有特殊的解析规则):

    Standard ML of New Jersey v110.83 [built: Thu May 31 09:04:19 2018]
    - Control.lazysml := true;
    [autoloading]
    [ ... boring details ...] 
    [autoloading done]
    val it = () : unit
    - open Lazy;
    [autoloading]
    [autoloading done]
    opening Lazy
    
      datatype 'a susp = $ of 'a
    - fun plus (x, y) = $(case (x, y) of ($m, $n) => m + n);
    val plus = fn : int susp * int susp -> int susp
    -  val x = plus($4, $5);
    val x = $$ : int susp
    - fun force ($x) = x;
    val force = fn : 'a susp -> 'a
    - force x;
    val it = 9 : int
    - fun lazy plus ($x, $y) = $ (x + y);
    val plus = fn : int susp * int susp -> int susp
    val plus_ = fn : int susp * int susp -> int
    

    请注意,这不会记住 plus

    【讨论】:

    • 这行得通! plus 函数没有被记忆,但暂停是,例如,fun lazy delayed ($x) = $(print "Evaluating...\n"; x),然后将其与val x = delayed ($5) 绑定,并强制它两次force x; force x 只打印一次。谢谢!但是,我不明白为什么fun delayed x = $(case x of ($q) => (print "Evaluating...\n"; q)) 不起作用。当将其绑定为val q = delayed ($4) 时,在被强制之前已经打印(尽管它仍然被记忆)。但我想知道为什么打印没有暂停。
    • 您能否详细说明为什么Control.lazysml := trueopen Lazy 都是必要的以及它们的作用?
    • 前者在编译器中启用惰性求值。 open Lazy; 打开Lazy 模块,因此您可以使用非限定名称。 (另外,请注意 lazy 不是函数。)
    猜你喜欢
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 2012-06-02
    • 2015-09-06
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多