Sml 多态函数

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 ([

我试图在类型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 ([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 对这件事有耐心或耐心。