1

I am trying to write a simple add function that takes two real lists and adds the matching indices together and generates a real list, but for some reason I can't get it to accept real lists as the parameters, but instead only int lists.

fun add (nil, _) = nil
  | add (_, nil) = nil
  | add (a :: b, x :: y) = (a + x) :: add (b,y)

When I try running my test input, val addTest = add([1.0, 2.0, 3.0], [0.1, 0.2, 0.3]); it gives me:

Error: operator and operand do not agree [tycon mismatch]
   operator domain: int list * int list
   operand:         real list * real list

And I am just curious as to why SML is defaulting to an int list even though the "+" operand is used for both reals and ints. Shouldn't it be accepting `a list instead of just int lists?

0

2 Answers 2

2

Yes, + (along with other arithmetic operators) is overloaded but not parametrically polymorphic.

So you can do 1.0 + 1.0 and 1 + 1 and they give a real and an int respectively.

But fun f x y = x + y can infer to either, so the compiler defaults to the int overload.

As an addition to your own answer, you can do with a single : real in your code:

fun add ([], _) = []
  | add (_, []) = []
  | add (x::xs, y::ys) = (x + y : real) :: add (xs, ys)

and it will infer that you must mean real in all the other places, too.


You could generalise this operation into one called 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
Sign up to request clarification or add additional context in comments.

Comments

1

I found out that the default behavior for SML in a case like this is to default to int behavior, so if you have an operand that works for either reals or ints it will be evaluated as an int. As for the method above I was able to get my desired behavior by specifying the parameters in the tuple to be real lists like so:

fun add (nil, _) = nil
  | add (_, nil) = nil
  | add (a::b : real list, x::y : real list) = (a + x) :: add (b,y)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.