元组访问:找不到固定的记录类型
tuple access: Can't find a fixed record type
我编写了一个应该接收元组列表的函数。我使用 #
访问元组的组件并且代码编译:
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
)
您的第一个代码 不会 编译,至少 SML/NJ:
如果你让它编译,那么它一定是在 SML 的非标准扩展中。
您的两个定义的问题在于,在 SML 中没有 tuple
任意元数的多态概念。您可以编写函数来处理对列表。您可以编写函数来处理三元组列表。但是——您不能编写同时处理成对列表和三元组列表的函数(至少如果您的函数尝试将这些 pairs/triples 作为元组处理)。
一个解决方案是摆脱 #
并使用模式匹配来提取组件:
fun validate [] = true
| validate ((x,y)::t) =
if x = 1 then
true
else
false
但是,如果您真的想编写一个可以多态地应用于成对列表或三元组列表(或四元组,...)的函数,最简单的方法是表示成对、三元组、等作为列表而不是元组。包含未指定大小列表的列表在 SML 中不是问题。
尽量减少这种情况,因为我在 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
编译器无法确定 record 的类型
其中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;
我编写了一个应该接收元组列表的函数。我使用 #
访问元组的组件并且代码编译:
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
)
您的第一个代码 不会 编译,至少 SML/NJ:
如果你让它编译,那么它一定是在 SML 的非标准扩展中。
您的两个定义的问题在于,在 SML 中没有 tuple
任意元数的多态概念。您可以编写函数来处理对列表。您可以编写函数来处理三元组列表。但是——您不能编写同时处理成对列表和三元组列表的函数(至少如果您的函数尝试将这些 pairs/triples 作为元组处理)。
一个解决方案是摆脱 #
并使用模式匹配来提取组件:
fun validate [] = true
| validate ((x,y)::t) =
if x = 1 then
true
else
false
但是,如果您真的想编写一个可以多态地应用于成对列表或三元组列表(或四元组,...)的函数,最简单的方法是表示成对、三元组、等作为列表而不是元组。包含未指定大小列表的列表在 SML 中不是问题。
尽量减少这种情况,因为我在 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 编译器无法确定 record 的类型 其中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;