1
votes

I'm having trouble writing a function that will take a list of functions and an argument, then call each function with the passed argument, returning a list of the results of the calls. Example: build [f, g, h] 2 would return this, but with the functions called and the results instead of the call: [f(2), g(2), h(2)] Using SML/NJ, by the way.

First I tried many variants of this pattern:

fun build functions TheArgument = if functions = [] then [] else
    [hd(functions) TheArgument] @ build tl(functions) TheArgument;

But it gave the following error:

stdIn:2.9-2.36 Error: operator is not a function [equality type required]
  operator: ''Z
  in expression:
    (hd functions) TheArgument
stdIn:1.10-2.70 Error: case object and rules don't agree [tycon mismatch]
  rule domain: ''Z list * 'Y
  object: ('X list -> 'X list) * 'W
  in expression:
    (case (arg,arg)
      of (functions,TheArgument) =>
           if functions = nil then nil else (<exp> :: <exp>) @ <exp> <exp>)

Finally, I gave up and tried to do some research. I found the following question: Higher Order Functions in SML/NJ

I tried redefining it as this:

fun build [] argument = []
|   build f::rest argument = [f(argument)] @ build rest argument;

But then the compiler spits this:

stdIn:2.14-2.16 Error: infix operator "::" used without "op" in fun dec
stdIn:1.10-2.67 Error: clauses don't all have same number of patterns
stdIn:2.14-2.16 Error: data constructor :: used without argument in pattern
stdIn:1.10-2.67 Error: types of rules don't agree [tycon mismatch]
  earlier rule(s): 'Z list * 'Y -> 'X list
  this rule: ('W -> 'V) * 'U * 'T * 'W -> 'V list
  in rule:
    (f,_,rest,argument) => (f argument :: nil) @ (build rest) argument

What am I doing wrong?

I'm at a serious loss here, I can deal with cryptic Java/C error messages, but this is just too alien to me.

p.s.: The function cannot be called via build(functions, argument), it NEEDS to be two arguments and not a tuple of 2 arguments.

2
Note that instead of using append (@) to add one element infront of a list i kind, you should use cons (::) instead. In the general case you should always avoid using append when possible. It is especially important if the right hand list is big, due to the uncured running time. In such a case you should produce the list in reverse order, and then reverse it when you are done.Jesper.Reenberg
The only thing you forgot in your final version was to put parenthesis around the pattern f::rest. Without those your second equation for build has four arguments: f, ::, rest, argument (instead of two, as indicated by the first equation). And that is exactly what the compiler was telling you (in his on words) ;)chris

2 Answers

1
votes
stdIn:2.14-2.16 Error: infix operator "::" used without "op" in fun dec

this above error is because of you have not used brakets outside of f::rest so this can be resolved as

fun build [] argument = []
|   build (f::rest) argument = [f(argument)] @ build rest argument;

it sml interpreter is not able understand that this is list hence ...

0
votes

One simple solution would be to use the standard higher-order function map:

fun build functions arg = map (fn f => f arg) functions;