SML NJ - 多态自定义列表类型和元素求和
SML NJ - Polymorphic custom list type and summing the elements
我正在学习多态性和 SML。我有点不确定如何在保持函数多态性的同时处理元素的求和。
说如果我有这个定义...
datatype 'a customList = nothing | customL of 'a * 'a customList
和这个列表...
val a = customL(2, customL(1, customL(3, nothing)))
我想我需要使用 (op +) 因为多态处理,但我无法使它们工作...
fun addElements (op +) nothing = 0
| addElements (op +) (customL(x, nothing) = x
| addElements (op +) (customL(x, xs)) = x + addElements xs
我也在想 "nothing" 的处理也可能会弄乱类型?
任何人都可以帮助让它工作吗?
更新
我想我更接近它了,但我不明白为什么我会收到错误...
exception EmptyList
fun addElements (op + ) nothing = raise EmptyList
| addElements (op + ) (customL(x, nothing)) = x
| addElements (op + ) (customL(x, xs)) = let val rest_of_list = addElements (op +) xs
in
(op + ) (x, rest_of_list)
end
你的作品有效,但我不认为它能达到你认为的效果。例如,
addElements (op - ) customL(2, customL(1, customL(3,nothing)))
计算为 4,并且
addElements (fn (x,y) => x) customL(2, customL(1, customL(3,nothing)))
计算为 2。
看情况,暂时忘掉customL
。该定义很好,但与 list
同构,因此要查看您的 addElements
发生了什么,用普通列表来编写它不会让人分心:
fun addElements (op + ) [] = raise Empty
| addElements (op + ) [x] = x
| addElements (op + ) (x::xs) = (op +)(x, addElements (op +) xs);
这基本上就是您所拥有的,除了它使用模式匹配而不是 let
绑定。 SML 接受为:
val addElements = fn : ('a * 'a -> 'a) -> 'a list -> 'a
请注意,该类型与加法或偶数(整型或实型)都没有任何关系。
发生的事情是您在定义正文中重新定义 (op +)
。 SML 大量使用 预定义标识符 而不是 保留名称 。这种区别似乎很迂腐,但这意味着您可以自由地重新定义任何东西:
val (op + ) = 5;
(op + ) * 7;
计算结果为 35。
在定义体(op +)
中可以是任何类型'a * 'a -> 'a
函数。因此——使用符号 +
和名称 addElements
具有误导性。最多可以说它反映了您的意图,但我认为这不是重新定义 built-in 运算符的充分理由,即使在本地范围内也是如此。
定义函数的误导性较小的方法更像是:
fun combineElements combiner [] = raise Empty
| combineElements combiner [x] = x
| combineElements combiner (x::xs) = combiner (x,combineElements combiner xs);
这里的名称选择清楚地表明它是一个多态函数,它使用有序对上的函数将列表组合成单个项目。
SML 有一个标准函数 foldl
可以完成所有这一切,甚至更多:
- foldl (op + ) 0 [1,2,3];
val it = 6 : int
- foldl (op + ) 0.0 [1.0, 2.0, 3.0];
val it = 6.0 : real
- foldl (op +) 0 [];
val it = 0 : int
注意它可以处理空列表。当我在评论中评论说您似乎正在尝试做一种 fold
但您想要 hard-wire 作为运算符选择加法时,这就是我的想法。
我正在学习多态性和 SML。我有点不确定如何在保持函数多态性的同时处理元素的求和。
说如果我有这个定义...
datatype 'a customList = nothing | customL of 'a * 'a customList
和这个列表...
val a = customL(2, customL(1, customL(3, nothing)))
我想我需要使用 (op +) 因为多态处理,但我无法使它们工作...
fun addElements (op +) nothing = 0
| addElements (op +) (customL(x, nothing) = x
| addElements (op +) (customL(x, xs)) = x + addElements xs
我也在想 "nothing" 的处理也可能会弄乱类型?
任何人都可以帮助让它工作吗?
更新
我想我更接近它了,但我不明白为什么我会收到错误...
exception EmptyList
fun addElements (op + ) nothing = raise EmptyList
| addElements (op + ) (customL(x, nothing)) = x
| addElements (op + ) (customL(x, xs)) = let val rest_of_list = addElements (op +) xs
in
(op + ) (x, rest_of_list)
end
你的作品有效,但我不认为它能达到你认为的效果。例如,
addElements (op - ) customL(2, customL(1, customL(3,nothing)))
计算为 4,并且
addElements (fn (x,y) => x) customL(2, customL(1, customL(3,nothing)))
计算为 2。
看情况,暂时忘掉customL
。该定义很好,但与 list
同构,因此要查看您的 addElements
发生了什么,用普通列表来编写它不会让人分心:
fun addElements (op + ) [] = raise Empty
| addElements (op + ) [x] = x
| addElements (op + ) (x::xs) = (op +)(x, addElements (op +) xs);
这基本上就是您所拥有的,除了它使用模式匹配而不是 let
绑定。 SML 接受为:
val addElements = fn : ('a * 'a -> 'a) -> 'a list -> 'a
请注意,该类型与加法或偶数(整型或实型)都没有任何关系。
发生的事情是您在定义正文中重新定义 (op +)
。 SML 大量使用 预定义标识符 而不是 保留名称 。这种区别似乎很迂腐,但这意味着您可以自由地重新定义任何东西:
val (op + ) = 5;
(op + ) * 7;
计算结果为 35。
在定义体(op +)
中可以是任何类型'a * 'a -> 'a
函数。因此——使用符号 +
和名称 addElements
具有误导性。最多可以说它反映了您的意图,但我认为这不是重新定义 built-in 运算符的充分理由,即使在本地范围内也是如此。
定义函数的误导性较小的方法更像是:
fun combineElements combiner [] = raise Empty
| combineElements combiner [x] = x
| combineElements combiner (x::xs) = combiner (x,combineElements combiner xs);
这里的名称选择清楚地表明它是一个多态函数,它使用有序对上的函数将列表组合成单个项目。
SML 有一个标准函数 foldl
可以完成所有这一切,甚至更多:
- foldl (op + ) 0 [1,2,3];
val it = 6 : int
- foldl (op + ) 0.0 [1.0, 2.0, 3.0];
val it = 6.0 : real
- foldl (op +) 0 [];
val it = 0 : int
注意它可以处理空列表。当我在评论中评论说您似乎正在尝试做一种 fold
但您想要 hard-wire 作为运算符选择加法时,这就是我的想法。