Closed AnthonyJacob closed 7 years ago
Not sure if this is a feature request or a comment, but variable number of arguments are expressible on the λ-calculus (and, thus, Moon)! Take this, for example:
sum:
roll: self. r. x.
(if (eql x 0)
r
(self self (add x r))
(self self 0))
(roll roll)
(sum 1 2 3 4 5 0)
This keeps summing all arguments it receives until it receives 0. Note, though, that this style is often considered bad; it introduces non-termination, has no normal form and wouldn't be typeable in a total fragment of Moon. What you want, 99% of the cases, is to fold over a list. For example, the right way to implement your andThen
is with
:
with: val. fns.
(for 0 (get fns "length") val i.result.
(get fns (nts i) result))
(with 3 [
(add 1)
(mul 2)
(add 100)
])
Notice how it looks basically the same, but now everything has a normal form. Your "multi-argument" map can be expressed the same way. For example, you could do this:
map: cons. matrix.
w: (get matrix "length")
h: (get (get matrix "0") "length")
(arrayGenerate 0 h i.
(for 0 w cons j. fn.
(fn (get (get matrix (nts j)) (nts i)))))
add3: a. b. c. (add a (add b c))
(map add3 [[1 2 3 4 5] [1 1 1 1 1] [10 10 10 10 10]])
Which uses add3
and sucks, but this could, too, be avoided with folds:
map: cons. nil. matrix.
w: (get matrix "length")
h: (get (get matrix "0") "length")
(arrayGenerate 0 h i.
(for 0 w nil j.
(cons (get (get matrix (nts j)) (nts i)))))
(map (add) 0 [[1 2 3 4 5] [1 1 1 1 1] [10 10 10 10 10]])
Here, map
performs a cross-column fold, you just need a 2 argument function and an initial value. No need to implement multiple-argument functions! In fact, that map
is quite useful, so it is now added to moon-base
under the name arrayCrossWith.
I have not realized until now, how powerful actually that feature is
It greatly reduces boilerplate:
map
,zipWith
,zipWith3
, ... become just singlemap
It leads to some pretty elegant one liners: transpose x =
(apply map list x)
And most importantly it allows you to resemble imperative blocks of code.