Concurrent Clean : Finger trees : listToTree

最近、こればっか。
リストを与えられて、そこからFinger treeを作るという関数 listToTree を作るとして、どうやって作るか。
単純には、pushLを連続的に適用して、

listToTree ls = foldr pushL Empty ls

とやって、pushLがO(1)なのでこれでもよいのだ(し、論文はこれで書いている)けれど、もっと効率よくできるはずだよね、という。
例えば、

listToTree ls
    # len = length ls
      pr = take 4 ls
      sf = drop (len - 4) ls
      md = take (len - 8) (drop 4 ls)
    = Deep pr (listToTree (nodes md)) sf

というのはどうか、とか思うわけだけれど、これには罠が。再帰するたびにlengthを呼んでいるのが微妙だ。もっとも、nodesがリストの長さを1/3にするので、線形であることに変わりはないのだけれど、嬉しくない。
じゃあ、こういうのはどうだろう?

listToTree ls
    # len = length ls
      (p,s) = splitAt (len / 2) ls
    = toTree p (reverse s)

toTree [] [] = Empty
toTree [a] [] = Single a
toTree [] [a] = Single a
toTree p s
    # (pr,pm) = splitAt 4 p
      (sf,sm) = splitAt 4 s
      pm = nodes pm
      sm = reverse_nodes sm
    = Deep pr (toTree pm sm) (reverse sf)

これならlengthを一回しか呼ばないし、リストの先頭にしかアクセスしないので、効率がいいんじゃないかな?