0
Follow
0
View

# Why am I getting this error for a function that simply adds a value to every integer in a list?

dudula2193 注册会员
2023-01-25 10:45

Your first pattern is defined in a curried way, whereas your second pattern uses a tuple way.

This ought to work:

``````fun list [] _ = []
| inclist l inc = map (fn x => x + inc) l;
``````

Notice I changed the pattern a bit, since when the list is empty we really don’t care what is the increment.

The truth is that this is probably what `map` already does, so most likely you can do away with the first pattern and just keep your mapping function pattern.

But anyways, now you can do:

``````inclist [] 100;
inclist [1,2,3] 5;
``````

Or alternatively you can define both function patterns using parenthesis.

ddl891106 注册会员
2023-01-25 10:45

Even this will do...

``````fun list inc = map (fn x => x + inc);
``````

May be not for now, but at some int in time while exploring the turf of `Higher-Order Functions`, this thing will be quite readily understandable.

stoopk 注册会员
2023-01-25 10:45

To clarify the earlier answer, given that the OP's code suggests a very novice level of SML knowledge:

Every SML function takes exactly one argument. Now, this sounds crazy because we've all seen functions that take more than one argument. There are two ways to reconcile these two things.

Functions are first class values in SML. We can easily write a fucntion without giving it a name.

``````fn x => x + 1
``````

We can bind this to a name.

``````val add1 = fn x => x + 1
``````

These functions have type `int -> int`. This type signature indicates that the function takes an int and returns an int.

There's a convenience syntax for this.

``````fun add1 x = x + 1
``````

If we want a function to take more than one argument... we can't. But our function that takes an int can return a function that takes an int and returns an int. The type signature of such a function would be `int -> int -> int`.

``````val add = fn x => fn y => x + y
``````

And again, there is a more convenient syntax for writing this.

``````fun add x y = x + y
``````

Calling this is simple:

``````add 42 27
``````

But we can partially apply the function. For example, providing `1` to `add` and getting back a function that adds `1` to whatever int sent to it.

``````val add1 = add 1
``````

SML's cousin OCaml uses currying almost exclusively. In SML, it's often more idiomatic to use tuples to provide multiple arguments to a function.

A tuple is a single value, but it contains multiple values which may have heterogenous types. Consider a simple tuples of two ints: `(3, 4)`. Syntactically tuples are surrounded by parentheses and the values are separates by commas.

A function that adds two ints like our earlier `add` function but uses tuples would look like:

``````fun add (x, y) = x + y
``````

In many cases, the space between the function name and the tuple is left out. To those familiar with C-like syntax, this can be misleading with regards to what's actually happening.

``````fun add(x, y) = x + y
``````

So, looking at the code you've written:

``````fun list [] 0 = []
| inclist (l, inc) = map (fn x => x + inc) l;
``````

The first line defines a curried function of type `'a list -> int -> 'a list` and the second defines a function of type `int list * int -> int list`.

Since these two signatures don't match, your code cannot compile.

``````fun inclist [] 0 = []
``````

You don't need to match the second argument as `0`. Incrementing an empty list by any amount will always be an empty list.

dingliwei888ddd 注册会员
2023-01-25 10:45

That's not your actual code – that code does not produce those messages.
Your actual code looks more like this:

``````fun list ([], 0) = []
| inclist (l, inc) = map (fn x => x + inc) l;

inclist [1,2,3,4,5] 1;
``````

with definition clauses of the same shape.
You have defined a function that takes a pair of an `int list` and an `int` and returns an `int list`.
As the error message says: `int list * int -> int list`.

Then you try to apply this function to something that is not such a pair.
`inclist [1,2,3,4,5] 1` is the same as `(inclist [1,2,3,4,5]) 1` - it first applies `inclist` to `[1,2,3,4,5]`, and then applies the result - which must be a function - to `1`.

Your first message refers to `inclist [1,2,3,4,5]`, and says that `[1,2,3,4,5]` is not an `int list * int`, which `inclist` needs.

The second message refers to your applying `inclist [1,2,3,4,5]` to `1`, when `inclist [1,2,3,4,5]` is not a function.
(It is slightly peculiar that polyml claims that `inclist [1,2,3,4,5]` is an `int list`, when it has a type error according to the previous message. One possible explanation is that polyml doesn't bother to check the type of the argument but goes "`inclist` applied to whatever argument is an `int list`".)

The solution is to either pass a pair like the function expects:

``````inclist ([1,2,3,4,5], 1)
``````

or to define the function in the "curried" manner:

``````fun inclist [] 0 = []
| inclist l inc = map (fn x => x + inc) l;

inclist [1,2,3,4,5] 1;
``````

On a side note, that first special case is unnecessary.
If you're worried about inefficiency, it makes more sense to special-case `0` than `[]` (avoiding zero-additions in a huge list can be beneficial; only avoiding it with the empty list is pointless).

``````fun inclist (l, 0) = l
| inclist (l, inc) = map (fn x => x + inc) l;
``````

but this will also do the job:

``````fun inclist (l, inc) = map (fn x => x + inc) l;
``````

dinsam6 注册会员

Publish Time
2023-01-25 10:45
Update Time
2023-01-25 10:45