SML NJ - 多态自定义列表类型和求和元素

时间:2016-01-04 03:55:35

标签: polymorphism sml smlnj

我正在学习多态性和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

我也在考虑处理"没有"也可能搞这种类型?

任何人都可以帮助让这个工作吗?

更新

我想我更接近它,​​但我不明白为什么我会收到错误...

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

1 个答案:

答案 0 :(得分:2)

你有什么作品,但我认为它不会像你认为的那样。例如,

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 

请注意,该类型与添加或偶数(int或real)没有任何关系。

发生的事情是您在定义正文中重新定义 (op +)。 SML大量使用预定义标识符而不是保留名称。区别似乎很迂腐,但这意味着你可以自由地重新定义任何东西:

val (op + ) = 5;
(op + ) * 7;

评估为35。

在定义的正文中(op +)可以是 'a * 'a -> 'a类型的任何函数。因此 - 使用符号+和名称addElements会产生误导。可以说最多的是它反映了你的意图,但我不认为这是重新定义内置运营商的充分理由,即使在本地范围内也是如此。

定义你的功能的一种误导性较小的方式更多的是:

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时,我想到了这一点,但是你想要选择加法作为运算符。