我试图构建一个拉动2个给定函数的函数,忽略较长列表的长度。
fun zipTail L1 L2 =
let
fun helper buf L1 L2 = buf
| helper buf [x::rest1] [y::rest2] = helper ((x,y)::buf) rest1 rest2
in
reverse (helper [] L1 L2)
end
当我这样做时,我收到了错误消息:
错误:条款的右侧与功能结果类型[圆形度]不一致
我很好奇,因为循环错误是什么,我应该如何解决这个问题。
答案 0 :(得分:3)
这里有很多问题
1)在helper buf L1 L2 = buf
中,模式buf L1 L2
将匹配所有可能的输入,使下一个子句(一旦调试)变为冗余。在上下文中,我认为你的意思是helper buf [] [] = buf
,但是在不同大小的列表的情况下,你会遇到非穷举匹配的问题。最简单的解决方法是将第二个子句(带有x::rest1
的子句)移动到顶行,然后使用第二个模式来捕获其中至少有一个列表为空的情况。
2)[xs::rest]
是一个模式,它匹配项目为非空列表的1项目列表。那不是你的注意力。您需要使用(,)
而不是[,]
。
3)reverse
应为rev
。
进行这些更改后,您的定义将变为:
fun zipTail L1 L2 =
let
fun helper buf (x::rest1) (y::rest2) = helper ((x,y)::buf) rest1 rest2
| helper buf rest1 rest2 = buf
in
rev (helper [] L1 L2)
end;
符合预期。
错误信息本身有点难以理解,但您可以这样想。在
helper buf [x::rest1] [y::rest2] = helper ((x,y)::buf) rest1 rest2
左侧括号中的内容是列表清单。因此,他们的类型为'a list list
,其中'a
是x
的类型。在x::rest1
中,rest1
的类型必须为'a list
,因为rest1
也会出现在与[x::rest1]
相同位置的等号的另一侧, rest1
的类型必须与[x::rest1]
的类型相同,即'a list list
。因此,rest1
必须同时为'a list
和'a list list
,这是不可能的。
如果您尝试理解'a list list = 'a list
,则需要使用'a
'a = 'a list
类型StringBuilder sample = new StringBuilder();
sample.append("DDD,FFFFFF,KKKK,LLLL).append("|")
.append("KKK,FFFFF,KKK,LLLL");
。这将是一个类型,其值由相同类型的值列表组成,并且该列表中的项的值本身必须是相同类型的元素列表...它是一个永远不会结束的粘性循环。
答案 1 :(得分:1)
您想要(x::rest1)
而不是[x::rest1]
。
问题是语法上的误解。
[foo]
将匹配其中只包含一个元素的列表foo
。x::rest1
将与列表中至少包含一个元素x
及其(可能为空)尾rest1
匹配。 这是您想要的模式。但模式包含一个中缀运算符,因此您需要在其周围添加一个括号。[x::rest1]
将与完全一个元素的列表匹配,该元素本身是至少一个元素的列表。这种模式虽然过于具体,但仍然有效,并且本身不会引发类型错误。您遇到循环错误的原因是编译器无法推断出rest1
的类型。因为它出现在::
模式构造函数的右侧,它必须是'列表,并且它本身就会发生,它必须是'a < / em>的。尝试unify 'a = '列表就像找到方程 x = x + 1 的解决方案。
你可能会说“好吧,只要'a ='列表列表列表列表...... 无限,如∞=∞+ 1 ,那就是解。”但Damas-Hindley-Milner type system并未将此无限构造视为明确定义的类型。创建单例列表[[[...x...]]]
需要无限量的括号,因此无论如何它都不是完全实用的。
一些简单的圆形例子:
fun derp [x] = derp x
:这是您的情况的简化,其中derp
的第一个参数中的模式表示列表,而x
表示元素的类型此列表必须与列表本身的类型相同。
fun wat x = wat [x]
:这是一个非常类似的情况,其中wat
采用'a 类型的参数,并使用'类型的参数调用自身列表。当然,'a 可以是'列表,但是'列表必须是'列表列表等等
正如我所说,由于语法上的误解,你得到了循环。列表模式。但循环不仅限于列表。它们是组合类型和自我引用的产物。这是一个没有列出Function which applies its argument to itself?列表的例子:
fun erg x = x x
:在这里,x
可以被认为是以'a 开头的类型,但是看到它作为一个函数应用到自身,它还必须有输入'a - &gt; “B 。但如果'a ='a - &gt; 'b ,然后'a - &gt; b =('a - &gt;'b) - &gt; 'b 和('a - &gt;'b) - &gt; b =(('a - &gt;'b) - &gt; b) - &gt; b ,依此类推。 SML编译器很快就会确定这里没有解决方案。这并不是说具有循环类型的函数总是无用的。作为newacct points out,将纯粹的匿名函数转换为递归函数实际上需要这样,就像在Y-combinator中一样。
内置ListPair.zip
顺便说一句是usually tail-recursive。