I have the function:
map(map(fn x =>[x])) [[],[1],[2,3,4]];
Which produces:
val it = [[],[[1]],[[2],[3],[4]]]
I don't understand how this function works. Doesn't each map function need both a function and a list? It seems that there isn't enough arguments for this to actually execute.
If I run:
map(fn x =>[x]) [[],[1],[2,3,4]];
I get:
val it = [[[]], [[1]], [[2,3,4]]];
Which makes more sense to me, as it takes each element in the list, and wraps it in another list. But when I put another map on it, it changes the output. Can anyone explain this to me? Thank you!
You said:
Well, keep in mind than, in Standard ML (and, in general, all applicative languages), there is no such thing as a "function of n parameters", for "n" other than 1. However, functions of more than one parameter can be simulated in two ways:
As functions of a single parameter that is a tuple or record. The original intended parameters can be recovered in the function's body by means of projection from the tuple or record.
As functions of the first parameter that return a function of the remaining parameters.
With this in mind, we check
map
's type in the REPL:(I use Poly/ML, not SML/NJ, but formatting issues aside, the output should be the same.)
No tuples, no records.
map
clearly takes the second approach to simulating a function of two parameters: it takes a function of type'a -> 'b
and returns another function of type'a list -> 'b list
.Now, here is the catch: For any function
foo
,map foo
is a function as well! Sincemap
can take any function as argument,map foo
is itself a perfectly legitimate argument formap
. Which means thatmap (map foo)
typechecks for any functionfoo
. In particular, this is true ifval foo = fn x => [x]
.You said:
If it typechecks, it runs.
You said:
Let's refactor your code a little bit, without changing its meaning:
Now we can analyze what every function (
foo
,bar
,baz
) does to its parameter:foo
takes a single elementx
and wraps it in a list data constructor.bar
takes a list of elements, wraps each element in a list data constructor, and returns a list with the resulting wrapped elements (a list of lists).baz
takes a (super)list of (sub)lists of elements, appliesbar
to every sublist, and returns a list with the results.Perform all of this manually to convince yourself that the result,
[[], [[1]], [[2], [3], [4]]]
, is indeed correct.