我试图在类型T上定义多态函数sum,其中类型T可以是int,real或类型T的列表.int和real的情况的总和应该按预期工作。对于T列表的情况,它应该返回两个列表的相应元素的总和(列表的长度应该相同)。
示例:
datatype T = INT of int | REAL of real | L of T list;
fun sum (x:T, x':T) = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L (x :: xs), L (y :: ys)) => L ((sum (x, y)) :: (sum (L xs, L
ys))
| (_,_) => REAL (0.0);
我写的功能如下:
expects: _ * [??? list]
but got: _ * [???]
in: :: (sum (x, y), sum (L xs, L ys))
unhandled exception: Fail: compilation aborted: parseAndElaborate reported errors
但对于上述功能,我收到错误:
构造函数应用于不正确的参数。
fun sum (x:T, x':T) = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L (x :: xs), L (y :: ys)) => L ((sum (x, y)) :: (sum (L xs,
L ys)) :: nil)
| (_,_) => REAL (0.0);
因此我通过添加nil来改变我的代码,如下所示。据我所知,错误的原因是cons运算符试图将T(INT或REAL)最终连接到T(INT或REAL)为(sum(x,y),sum(L xs) ,L ys))最终将通过递归调用INT或REAL来评估。因此我通过在最后添加nil(空列表)来改变我的代码
sum (L([INT(1)]), L([INT(3)]));
val it = L [INT 4,L []] : T
sum (L([INT(1),INT(2)]), L([INT(3),INT(4)]));
val it = L [INT 4,L [INT #,L #]] : T
但是对于这种情况,它对INT和REAL的行为正确,但对于多态列表则不行。 它对INT和REAL的行为正确(因为它们更容易实现)。对于列表部分,我想cons运算符存在一些问题,我无法找出解决方案。 我执行的测试用例及其输出如下:
{{1}}
P.S:请忽略最后一种情况(,)=> REAL(0.0)因为我稍后会处理类型不匹配的情况。
答案 0 :(得分:2)
这似乎是相互递归函数的一个很好的用例:
datatype T = INT of int | REAL of real | L of T list
fun sum (x, x') = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L ns, L ns') => L (sumLists (ns, ns'))
| (_, _) => ? (* mismatching types *)
and sumLists (x::xs, y::ys) = sum (x, y) :: sumLists (xs, ys)
| sumLists ([], []) = []
| sumLists (_, _) = ? (* mismatching lengths *)
由于不匹配类型导致REAL 0.0
似乎是一个问题。
例如,为什么sum (INT 2, L [INT 3])
应为REAL 0.0
?
为什么sum (INT 2, REAL 3.0)
应该REAL 0.0
?
如果对您的域有意义,请考虑添加“{1}}和INT
的替代”,或者更好地考虑将REAL
函数更改为< em> may 返回一个总和,如果它可以在树的所有级别上有意义地计算,即sum
。它归结为错误处理。
编写描述角落案例预期行为的测试。特别是在汇总不具有相同类型的值时,以及总结不匹配长度的列表。
您的示例看起来像测试:
val sum : T * T -> T option
除 val test1 = sum (L [INT 1], L [INT 3]) = L [INT 4]
val test2 = sum (L [INT 1, INT 2], L [INT 3, INT 4]) = L [INT 4, INT 6]
不是相等类型,因为它包含T
,因此您需要编写自己的等于运算符,该运算符使用epsilon test (nearlyEqual
)时您遇到real
,例如:
real
你的一些角落案例可能看起来像
fun eqT (INT x, INT y) = x = y
| eqT (REAL x, REAL y) = nearlyEqual(x, y, someEps)
| eqT (L (x::xs), L (y::ys)) = eqT (x, y) andalso eqT (L ys, L xs)
| eqT (L [], L []) = true
| eqT (_, _) = false