我正在尝试编写一个简单的添加函数,它接受两个真实的列表并将匹配的索引添加到一起并生成一个真实的列表,但由于某种原因,我不能让它接受真实的列表作为参数,而是只有int列表。
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a :: b, x :: y) = (a + x) :: add (b,y)
当我尝试运行我的测试输入时,val addTest = add([1.0, 2.0, 3.0], [0.1, 0.2, 0.3]);
它给了我:
Error: operator and operand do not agree [tycon mismatch]
operator domain: int list * int list
operand: real list * real list
我只是好奇为什么SML默认为一个int列表,即使“+”操作数用于实数和整数。它不应该接受`列表而不仅仅是int列表?
是的,+
(以及其他算术运算符)是重载但不是参数多态的。
所以你可以做1.0 + 1.0
和1 + 1
,他们分别给出一个真实和一个int。
但是fun f x y = x + y
可以推断出任何一个,所以编译器默认为int重载。
作为您自己答案的补充,您可以在代码中使用单个: real
:
fun add ([], _) = []
| add (_, []) = []
| add (x::xs, y::ys) = (x + y : real) :: add (xs, ys)
并且它将推断出你必须在所有其他地方都是真实的。
您可以将此操作概括为一个名为zipWith
的操作:
- fun zipWith f [] _ = []
| zipWith f _ [] = []
| zipWith f (x::xs) (y::ys) = f (x, y) :: zipWith f xs ys
> val ('a, 'b, 'c) zipWith = fn :
('a * 'b -> 'c) -> 'a list -> 'b list -> 'c list
- val add = zipWith (op + : real * real -> real)
> val add = fn : real list -> real list -> real list
- add [1.0, 2.0, 3.0] [4.0, 5.0, 6.0];
> val it = [5.0, 7.0, 9.0] : real list
我发现在这种情况下SML的默认行为是默认为int行为,所以如果你有一个适用于reals或ints的操作数,它将被评估为int。至于上面的方法,我能够通过将元组中的参数指定为真实列表来获得我想要的行为,如下所示:
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a::b : real list, x::y : real list) = (a + x) :: add (b,y)