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.

In your code, you've unnecessarily specialized your pattern-matching.

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;

About the Author

Question Info

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

Related Question

The ArcGIS API for JavaScript is already loaded (/init.js).

MERGE INTO错误“在DML操作期间检测到重复行”,但没有发现重复行

“typedef void(*wskfun)(const string)”是什么意思?


nginx 地址映射访问

beforeSend in axios


为什么JavaScript同时将vector定义为vector和undefined ?