我目前正在研究结合 Javascript 中的 monad 的惰性求值,以及可能从中演化出哪些用例。所以我尝试实现一个惰性类型,它实现了 functor/monad 类型类。相应的构造函数在其参数和结果中是惰性的。这是我想出的:
// a lazy type
// (() -> a) -> () -> b
const Lazy = thunk => () => thunk();
// (b -> a -> b) -> b -> Lazy a -> b
Lazy.fold = f => acc => tx => f(acc) (tx());
// (a -> b) -> Lazy a -> Lazy b
Lazy.map = f => tx => Lazy(() => f(tx()));
// Lazy (a -> b) -> Lazy a -> Lazy b
Lazy.ap = tf => tx => Lazy(() => tf() (tx()));
Lazy.of = Lazy;
// Lazy (Lazy a) -> Lazy a
Lazy.join = ttx => ttx();
// (a -> Lazy b) -> Lazy a -> Lazy b
Lazy.chain = ft => tx => Lazy.join(Lazy.map(ft) (tx));
// recursive bind (or chain in Javascript)
// Number -> (a -> b) -> a -> Lazy b
const repeat = n => f => x => {
const aux = m => y => m === 0
? Lazy(() => y)
: Lazy.chain(aux(m - 1)) (Lazy(() => f(y)));
return aux(n) (x);
};
// impure function to observe the computation
const inc = x => (console.log(++x), x);
// and run
console.log(repeat(5) (inc) (0)); // logs 1, 2, 3, 4, 5, () => thunk()
现在这显然没有意义,因为 Action 序列一点也不懒惰。 Lazy.join 只是过早地触发评估。因此,出现了以下问题:
我什至不确定我的研究是否有意义,所以请随意投票结束这个问题。
最佳答案
这取决于您所说的“实现惰性求值”是什么意思。你当然可以制作一个“延迟”类型,它将是一个单子(monad)。但通常我们将类型为 A -> State S B 的函数视为“从 A 到 B 的有状态函数”。对于 A -> Delay B 之类的东西,似乎对于参数 A 我们已经“强制”了它。看起来我们真的想要更像 Delay A -> Delay B 的东西。
事实证明,有多种方法可以将表达式转换为 monadic 样式。一种按值调用方式,这是通常的方式,一种按名称调用方式。 Phil Wadler 在他 1992 年的论文中对此进行了讨论 Comprehending Monads (PDF)。毫不奇怪,这些与一个类似的事实有关,即有两种转换为连续传递样式 (CPS) 的方式:按值调用和按名称调用。实际上,这些正是带有延续 monad 的 call-by-value/-name monadic 风格的翻译。 CPS 的目的是将目标实现语言的评估顺序与源语言的评估顺序分开。如果您使用按值调用 CPS 转换来实现源语言,那么无论目标语言的评估顺序是什么,它都将具有按值调用语义。同样,如果您使用按名称调用 CPS 转换,您同样会获得按名称调用语义,而不管目标语言的评估顺序如何。
我不知道当使用带有 Delay monad 的按值调用转换时,事情会如何发展,但我怀疑它通常会“稍微”偏离并且“更正”,它将更倾向于按名称进行翻译。
关于javascript - 惰性求值可以通过 monadic 类型实现吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44289542/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)