ホッテントリっぽいタイトル付けてみました。中身がホッテントリでないことは言うまでもありません。
関数型言語の基本データと言えばリスト。Maximaにももちろんリストがあり、しかも式もリスト表現なので式もリスト操作で色々できます。
Haskell | Maxima |
(:) | cons |
== | = |
null | emptyp |
l1 ++ l2 | append(l1, l2) |
concat ls | apply(append, ls) |
reverse | reverse |
length | length |
head | first |
tail | rest |
last | last |
init l | rest(l, -1) |
take n l | rest(l, n - length(l)) |
drop | rest |
splitAt n l | [rest(l, n - length(l)), rest(l, length(l) - n - 1)] |
l !! i | l[i] |
map | map/maplist |
sum l | lsum(x, x, l) |
filter p l | makelist(l[i], i, sublist_indices(l, p) |
zip | map(lambda([x, y], [x, y]), l1, l2) |
zipWith | map/maplist |
foldl/foldl1 | lreduce/xreduce |
foldr/foldr1 | rreduce |
tree_reduce | |
scanl | |
scanr | |
unzip | |
fmap | fullmap |
map系はともかく、関数型言語のもう1つの基本fold系が手薄いこともあり、拡張パッケージを作りました。
/* functional package */ take(n, list) := rest(list, n - length(list))$ drop(n, list) := rest(list, n)$ splitAt(n, list) := [take(n, list), drop(length(list) - n - 1, list)]$ filter(p, list) := makelist(list[i], i, sublist_indices(list, p))$ scanl(binary_op, init, list) := cons(init, if emptyp(list) then [] else scanl(binary_op, binary_op(init, list[1]), rest(list, 1)))$ scanr(binary_op, init, list) := if emptyp(list) then [init] else block([x], x : scanr(binary_op, init, rest(list, 1)), cons(binary_op(list[1], x[1]), x))$ zip(list1, list2) := map(lambda([x, y], [x, y]), list1, list2)$ unzip(list) := foldr(lambda([x, y], [cons(x[1], y[1]), cons(x[2], y[2])]), [[], []], list)$
Haskellの糖衣構文が素晴らしいことがよくわかりました…