SML / NJ - 使用foldr的一个行长度函数

时间:2015-11-02 17:45:57

标签: sml fold smlnj ml

我试图创建一个长度函数,类似于已经包含在ML中的长度函数。我的限制是它必须在一行上完成并使用map,foldl或foldr。

现在我的代码行看起来像这样:

val mylength = foldr ( fn(x,y) => 1+y) 0;

我绝不是ML的专家,但到目前为止,我的理由是:

根据我的理解,foldr将从列表的最后一项开始,将其作为我函数中的x参数传递,并使用0作为初始y值。然后应该在y值上加1,基本上忽略x。理论上,我相信这会给我我的总长度。但是我收到以下错误:

 stdIn:136.5-136.37 Warning: type vars not generalized because of
   value restriction are instantiated to dummy types (X1,X2,...)
 val mylength = fn : ?.X1 list -> int

我的一个大问题是如何以一种可以接受任何类型的列表的方式来创建这个函数。

如果有人能就如何解决这个问题提出一些建议,我会很感激,或许我仍然无法围绕ML的编程风格。

3 个答案:

答案 0 :(得分:4)

你的功能本质上是正确的。根据您使用的解释器,它将接受给定的代码或拒绝它。例如,在CloudML上运行代码就可以了。 要避免此问题,请将其定义为如下函数:

def create @myusers = params[:user] @myusers.each do User.create(user_params) end def user_params params.permit(:name,:address ) end

来自华盛顿大学的丹尼尔格罗斯曼在他的一个课程中解释说,这个错误与可变引用有关。遗憾的是,我无法回想起他在哪一课中提到过这一点。

您可以同时考虑以下内容:

答案 1 :(得分:1)

foldlfoldr提供了一些standard definitions

fun foldr f e []      = e
  | foldr f e (x::xr) = f(x, foldr f e xr);

fun foldl f e []      = e
  | foldl f e (x::xr) = foldl f (f(x, e)) xr;

可以手动将您的功能应用于短名单,看看术语重写是如何展开的:

foldr (fn(_,y) => 1+y) 0 [5,6,7]
(fn(_,y) => 1+y) (5,foldr (fn(_,y) => 1+y) 0 [6,7])
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,foldr (fn(_,y) => 1+y) 0 [7]))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,(fn(_,y) => 1+y) (7,foldr (fn(_,y) => 1+y) 0 [])))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,(fn(_,y) => 1+y) (7,0)))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,1))
(fn(_,y) => 1+y) (5,2)
3

使用foldr,您可以看到元素7首先被解析(它从右向左折叠),并且表达式的长度(以及堆栈内存)按比例增长名单。使用foldl,您可以看到5首先被解析(它从左到右折叠),并且表达式的长度是常量。在这两种情况下,匿名函数的参数的第一部分都将被丢弃。

foldl (fn(_,y) => 1+y) 0 [5,6,7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(5, 0)) [6,7]
foldl (fn(_,y) => 1+y) 1 [6,7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(6, 1)) [7]
foldl (fn(_,y) => 1+y) 2 [7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(7, 2)) []
foldl (fn(_,y) => 1+y) 3 []
3

不可否认,lambdas使整个事情变得混乱。鉴于定义

fun plus1(_,y) = 1+y

以下重写相当但更清晰。

foldr plus1 0 [5,6,7]
plus1 (5, foldr plus1 0 [6,7])
plus1 (5, plus1 (6, foldr plus1 0 [7]))
plus1 (5, plus1 (6, plus1 (7, foldr plus1 0 [])))
plus1 (5, plus1 (6, plus1 (7, 0)))
plus1 (5, plus1 (6, 1))
plus1 (5, 2)
3

foldl plus1 0 [5,6,7]
foldl plus1 (plus1 (5,0)) [6,7]
foldl plus1 1 [6,7]
foldl plus1 (plus1 (6,1)) [7]
foldl plus1 2 [7]
foldl plus1 (plus1 (7,2)) []
foldl plus1 3 []
3

答案 2 :(得分:0)

一个稍微长一点的解决方案(我想通过考虑map如何相关来提出这个解决方案):

fun len xs = (foldr op+ 0 o map (fn x => 1)) xs;

此处o是组合运算符。我想写

val len  = foldr op+ 0 o map (fn x => 1); 

以便模仿Haskell中流行的无点样式,但遇到了与原始定义相同的值限制。