読者です 読者をやめる 読者になる 読者になる

読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

Maximaを関数型言語に変える10の拡張(リスト操作)

ホッテントリっぽいタイトル付けてみました。中身がホッテントリでないことは言うまでもありません。


関数型言語の基本データと言えばリスト。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の糖衣構文が素晴らしいことがよくわかりました…