元组访问:无法找到固定记录类型

时间:2016-04-28 14:35:15

标签: tuples sml records

我编写了一个应该接收元组列表的函数。我使用#访问元组的组件,代码编译:

fun recheck ([], n) = []
  | recheck (h::t, n) = 
    if ((#1 h) *  (#1 h)) +  ((#2 h) * (#2 h)) = n then
    h::recheck(t, n)
    else
    recheck(t, n)

但另一个基本上做同样事情的函数,即接收元组列表并访问它们会导致错误。

fun validate ([]) = true
  | validate (h::t)  = 
    if 1 = (#1 h) then
    true
    else
    false

Can't find a fixed record type.   Found near #1

这里有什么区别,为什么后者会导致错误?

修改

第一个函数实际上不能单独编译。

但整个片段确实如此:

fun drop ([], n) = []
  | drop (h::t, 0) = h::t
  | drop (h::t, n) =
    drop(t, n-1) 

fun sts_linear (y, n) =
  if y < (Math.sqrt(n)+1.0) then
      let
      (* x^2 + y^2 = n => x = sqrt(n-y^2) *)
      val x = Math.sqrt(n - (y * y));
      val xr  = Real.realRound(x);
      in
  if (abs(x - xr) < 0.000000001)  then
          [(Real.trunc xr, Real.trunc y)]@sts_linear (y+1.0, n)
      else
          (
        []@sts_linear (y+1.0, n)
          )
      end
  else []

fun recheck ([], n) = []
  | recheck (h::t, n) =
    if ((#1 h) *  (#1 h)) +  ((#2 h) * (#2 h)) = n then
    h::recheck(t, n)
    else
    recheck(t, n)

fun sts (n) =
  (
    let
        val pairs = sts_linear(0.0, Real.fromInt n);
    in
        recheck(drop(pairs, Real.ceil( Real.fromInt (length(pairs))/2.0 ) ), n)
    end
  )

2 个答案:

答案 0 :(得分:2)

你的第一个代码没有编译,至少使用SML / NJ:

enter image description here

如果你要编译它,那么它必须是SML的非标准扩展。

两个定义的问题在于SML中没有tuple任意arity的多态概念。您可以编写函数来处理对列表。您可以编写函数来处理三元组列表。但是 - 你不能写函数同时在三元组和三元组列表上工作(至少如果你的函数试图用这些对/三元组作为元组做事)。

一种解决方案是摆脱#并使用模式匹配来提取组件:

fun validate [] = true
|   validate ((x,y)::t)  = 
        if x = 1 then
            true
        else
            false

但是,如果你真的想编写一个可以多态地应用于对列表或三元组列表(或四元组......)的函数,最简单的方法是表示对,三元组等。作为列表而不是元组。包含非指定大小列表的列表在SML中不是问题。

答案 1 :(得分:0)

尝试最大限度地减少这种情况,因为我在SML / NJ中看到了以下工作 我并不知道它实际上是编译器扩展

val p1 = {x=0, y=0};
val p2 = {x=1, y=1};
val p3 = {x=1, y=1, z=1};

从编译器错误的角度来看,存在一个笨拙的构造 没有多少语言有错误以这种方式工作, 因为该函数有效,但会产生类型错误 除非存在函数调用来解决 'record'的类型,因此要解决错误,必须添加更多代码。

fun getFoo(field) = fn record => field record;

没有以下实际调用getX 编译器无法确定记录的类型 其中ALL字段的完整类型信息 必须为编译器知道记录,而不仅仅是#x字段。

let val getX = getFoo(#x);
    val x1 = getX(p1);
    val x2 = getX(p2);
    val x3 = getFoo(#x)(p3);
in () end;

而以下注释掉的代码段会因为类型而导致错误 p1和p3是不同的,所以不同的getFoo调用 是必需的

(*
let val getX = getFoo(#x);
    val x1 = getX(p1);
    val x3 = getX(p3);
in () end;
*)

以下内容不充分,因为它永远无法解析记录。

let val getX = getFoo(#x) in () end;