【发布时间】:2016-03-02 02:59:50
【问题描述】:
我遇到了一个元组问题,给定一对元组列表,它应该变成一对列表:即[(1,2),(3,4),(5,6)] 应该返回([1,3,5],[2,4,6])。
我尝试使用此代码解决它:
fun convert L = foldl (fn(a,b) => #1a::b) [] L;
但我收到一条错误消息:未解析的弹性记录。 谁能解释我为什么会得到这个以及如何解决它?
【问题讨论】:
我遇到了一个元组问题,给定一对元组列表,它应该变成一对列表:即[(1,2),(3,4),(5,6)] 应该返回([1,3,5],[2,4,6])。
我尝试使用此代码解决它:
fun convert L = foldl (fn(a,b) => #1a::b) [] L;
但我收到一条错误消息:未解析的弹性记录。 谁能解释我为什么会得到这个以及如何解决它?
【问题讨论】:
查看a,编译器可以判断它应该是一个元组(因为您调用的是#1a),但它无法判断它有多大。 SML 类型系统不允许未知大小的元组;你需要明确a 是一对。
虽然你可以通过给a 一个类型声明来解决这个问题,但更好的方法是模式匹配它。不要将参数定义为(a,b) 并使用#1a 和#2a,而是将参数定义为((x,y),b) 并使用x 和y。
不过,您的解决方案还有另一个问题。您的函数正在将该对的第一个元素添加到结果列表中,但您忽略了第二个元素 (#2a),并且您的结果缺少第二个列表。你传递给foldl的函数应该是fn ((x,y),(u,v)) => ...,你的初始值应该是([],[])。
这个神秘的错误消息“未解析的弹性记录”的原因是 SML 中的元组被实现为带有整数标签的记录。元组 (a,b) 与记录 {1=a,2=b}相同。事实上,如果你在 SML/NJ shell 中输入{1=1,2=2},它会返回
val it = (1,2) : int * int
所以当您说#1a 时,您实际上是在说“从记录a 中提取标签为1 的元素”。
SML/NJ 没有record polymorphism 的概念。它知道a 必须是一条记录,并且此记录类型必须至少包含标签1(可能还有其他标签),但在SML/NJ 类型系统中无法表达这一点。
因此编译器需要知道记录的确切结构才能推断a 的类型,如果无法确定,则会抛出“未解析记录”错误。
【讨论】:
我手边没有 SML 解释器,但我认为您正在寻找 unzip。试试:
unzip([(1,2), (3,4), (5,6)]);
IIRC,“未解决的弹性记录”与您在这里没有使用的记录匹配有关?!查看 smlnj 的错误文档 (http://www.smlnj.org/doc/errors.html)。您需要在底部附近搜索错误[99]。
【讨论】:
- ListPair.unzip([(1,2), (3,4), (5,6)]);
> val it = ([1, 3, 5], [2, 4, 6]) : int list * int list
【讨论】: