Julia で scanl を使いたい

Julia で scanl に相当するものが見当たらなかったので、勉強がてら、考えてみました。

foldl が参考になるのではないかと思ってソースを見てみたところ、以下のようになっています。

foldl(op, v0, itr) = mapfoldl(identity, op, v0, itr)
mapfoldl(f, op, v0, itr) = mapfoldl_impl(f, op, v0, itr, start(itr))
function mapfoldl_impl(f, op, v0, itr, i)
  if done(itr, i)
    return r_promote(op, v0)
  else
    (x, i) = next(itr, i)
    v = op(r_promote(op, v0), f(x))
    while !done(itr, i)
      @inbounds (x, i) = next(itr, i)
      v = op(v, f(x))
    end
  end
end

色々呼び出していますが、f は map 用の関数で、op は v に結果を次々と付け加えていく関数と考えれば良さそう。
Haskell と(雰囲気だけですが)対応させると、こんな感じでしょうか。

itr :: (Ix i) => (b, i)
f :: b -> a
v :: a
op :: a -> a -> a  -- mappend 相当
mapfoldl f op v0 itr = foldl op v0 $ map f itr

scanl を作るためには、2つの引数を取る関数とmappend が必要ですが、 mapreduce には前者がないので、これで scanl を実現するのはちょっと難しそうです。

以上を踏まえ、素直に書くことにしました。こんな感じです。

 function scanl{T}(op, v0 :: T, xs)
   function scanList(op, vs, xs)
     isempty(xs) ? vs : scanList(op, [vs; op(vs[end], xs[1])], xs[2:end])
   end
   scanList(op, [v0], xs)
 end

再帰を使っていますが、foldl の実装を見ると素直にループを回した方が良いのかもしれません。この辺りも、Julia なら簡単に検討できるはずなので、いずれやってみようと思います。