Sml 多态函数
我试图在类型T上定义一个多态函数sum,其中类型T可以是int、real或类型T的列表。int和real情况下的sum应该按预期工作。对于T的列表,它应该返回两个列表的对应元素之和。列表的长度应该相同 示例:Sml 多态函数,sml,ml,Sml,Ml,我试图在类型T上定义一个多态函数sum,其中类型T可以是int、real或类型T的列表。int和real情况下的sum应该按预期工作。对于T的列表,它应该返回两个列表的对应元素之和。列表的长度应该相同 示例: sum (INT 2, INT 3) = INT 5 sum (REAL 2.3, REAL 3.4) = REAL 5.7 sum(L [2, 3, 4], L [3, 4, 5]) = L [5, 7, 9] sum(L L([2, 3, 4], [2, 3, 4]), L ([
sum (INT 2, INT 3) = INT 5
sum (REAL 2.3, REAL 3.4) = REAL 5.7
sum(L [2, 3, 4], L [3, 4, 5]) = L [5, 7, 9]
sum(L L([2, 3, 4], [2, 3, 4]), L ([3, 4, 5], [3, 4, 5]) = L ([5, 7, 9], [3, 4, 5])
我编写的函数如下所示:
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);
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
但对于上述函数,我得到了错误:
构造函数应用于不正确的参数
expects: _ * [??? list]
but got: _ * [???]
in: :: (sum (x, y), sum (L xs, L ys))
unhandled exception: Fail: compilation aborted: parseAndElaborate reported errors
因此,我更改了代码,添加了nil,如下所示。据我所知,产生错误的原因是cons运算符试图将T INT或REAL连接到T INT或REAL,最终作为sum x,y,sum L xs,L ys通过递归调用INT或REAL来计算。因此,我修改了代码,在最后添加了nil空列表
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);
但在这种情况下,它对INT和REAL的行为是正确的,但对多态列表则不正确。
它对INT和REAL的行为正确,因为它们更易于实现。对于列表部分,我猜cons运算符存在一些问题,我无法找到解决方案。
我执行的测试用例及其输出如下:
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);
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
请忽略最后一个例子,=>REAL 0.0,因为我稍后会处理类型不匹配的例子
这似乎是相互递归函数的一个很好的用例:
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 *)
由于类型不匹配而导致的实际0.0似乎是个问题
例如,为什么总和INT 2,L[INT 3]应该是实数0.0
为什么总和INT 2,REAL 3.0应该是REAL 0.0
考虑添加一个It和Realt的替代值,如果这对你的域是有意义的,那就没有价值了,或者,更好的是,如果它可以有意义地在树的所有层次上计算,即Valth:T*T->T选项,那么可以考虑改变和函数来返回一个和。这归结为错误处理
编写测试来描述您的案例的预期行为。特别是,当对不具有相同类型的值求和,以及对长度不匹配的列表求和时 作为测试,您的示例如下所示: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不是相等类型,因为它包含实数,所以您需要编写自己的相等运算符,在遇到实数时使用,例如:
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
你的一些角落案例可能看起来像
val case1 = sum (INT 2, REAL 3.0)
val case2 = sum (INT 2, L [])
val case3 = sum (INT 2, L [INT 3])
val case4 = sum (L [INT 1], L [INT 1, INT 2])
val case5 = sum (L [INT 1], L [INT 1, REAL 2.0])
val case6 = sum (L [], L [L []])
这似乎是相互递归函数的一个很好的用例:
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 *)
由于类型不匹配而导致的实际0.0似乎是个问题
例如,为什么总和INT 2,L[INT 3]应该是实数0.0
为什么总和INT 2,REAL 3.0应该是REAL 0.0
考虑添加一个It和Realt的替代值,如果这对你的域是有意义的,那就没有价值了,或者,更好的是,如果它可以有意义地在树的所有层次上计算,即Valth:T*T->T选项,那么可以考虑改变和函数来返回一个和。这归结为错误处理
编写测试来描述您的案例的预期行为。特别是,当对不具有相同类型的值求和,以及对长度不匹配的列表求和时 作为测试,您的示例如下所示: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不是相等类型,因为它包含实数,所以您需要编写自己的相等运算符,在遇到实数时使用,例如:
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
你的一些角落案例可能看起来像
val case1 = sum (INT 2, REAL 3.0)
val case2 = sum (INT 2, L [])
val case3 = sum (INT 2, L [INT 3])
val case4 = sum (L [INT 1], L [INT 1, INT 2])
val case5 = sum (L [INT 1], L [INT 1, REAL 2.0])
val case6 = sum (L [], L [L []])
这些不是测试用例。测试用例将预期值与实际值进行比较。你没有说它们是如何或为什么不起作用的,因此人们只能通过猜测你认为错误是什么来帮助你。我编辑了这个问题,使它更清楚。它变得不那么清楚:没有问题。你的测试不起作用,L[2,3,4]应该是L[1[2,3,4],你不能比较实数是否相等;你真的读过我的答案吗?。由于您编辑了主要代码段,因此在L模式上没有递归的基本情况,这使得它比您编辑之前更漂亮但更破碎。StackOverflow不能很好地执行前后逐渐消除错误消息的过程;你可能需要一位导师或耐心来做这件事。这些不是测试案例。测试用例将预期值与实际值进行比较。你没有说它们是如何或为什么不起作用的,因此人们只能通过猜测你认为错误是什么来帮助你。我编辑了这个问题,使它更清楚。它变得不那么清楚:没有问题。你的测试不起作用,L[2,3,4]应该是L[1[2,3,4],你不能比较实数是否相等;你真的读过我的答案吗?。由于您编辑了主要代码段,因此在L模式上没有递归的基本情况,这使得它比您编辑之前更漂亮但更破碎。StackOverflow不能很好地执行前后逐渐消除错误消息的过程;你可能需要一个tu 对这件事有耐心或耐心。