ML多态函数

时间:2018-06-14 06:31:22

标签: sml ml

我试图在类型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)因为我稍后会处理类型不匹配的情况。

1 个答案:

答案 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