Home About Contact
TypeScript , Functional Programming , Haskell

配列の要素をひっくり返す reverse を foldl, foldr で実装

JavaScript で...というか TypeScript で 配列の要素をひっくり返す には list.reverse() すればよいだけなのだが、この方法では元の配列もひっくり返る(破壊される)らしい。 list.toReversed() を使えば問題ないらしい。

reverse を使う:

const list0 = [1,2,3,4,5]

const list1 = list0.reverse()
console.log(list1) // [ 5, 4, 3, 2, 1 ] ひっくり返った
console.log(list0) // [ 5, 4, 3, 2, 1 ] ひっくり返った!! (この挙動は受け入れ難い)

toReversed を使う:

const list1 = list0.toReversed()
console.log(list1) // [ 5, 4, 3, 2, 1 ] ひっくり返った
console.log(list0) // [ 1, 2, 3, 4, 5 ] 元のまま

foldl でひっくり返す

deno を使います。

$ deno --version
deno 2.4.1 (stable, release, x86_64-unknown-linux-gnu)
v8 13.7.152.6-rusty
typescript 5.8.3

underscore js を使えるようにする:

$ deno add npm:underscore

foldl を使ってひっくり返す:

// main.ts

import { foldl } from 'underscore'

const list0: number[] = [1,2,3,4,5]

const list1: number[] = foldl(list0, (acc: number[], item: number): number[] => {
    return [item].concat(acc)
}, [] as number[])


console.log(list1) // [ 5, 4, 3, 2, 1 ]
console.log(list0) // [ 1, 2, 3, 4, 5 ] 元のまま

実行する:

$ deno run main.ts
[ 5, 4, 3, 2, 1 ]
[ 1, 2, 3, 4, 5 ]

型を明示して書いた方が書くときはわかりやすいがコードを読むときは冗長すぎでうっとうしい。

型を省略して簡潔に書けば次のとおり:

import { foldl } from 'underscore'

const list0 = [1,2,3,4,5]
const list1 = foldl(list0, (acc, item) => [item].concat(acc), [])

console.log(list1) // [ 5, 4, 3, 2, 1 ]
console.log(list0) // [ 1, 2, 3, 4, 5 ] 元のまま

結局左から順に折り畳み( foldl )つつ新しい配列を生成していくのだが、そのとき現在対象となっている item を(生成する配列の)先頭に配置していくだけの話。

foldr

右から畳むとさらに簡単にかけるのでついでに試した。

import { foldr } from 'underscore'

const list0 = [1,2,3,4,5]
const list1 = foldr(list0, (acc, item) => acc.concat([item]), [])

console.log(list1) // [ 5, 4, 3, 2, 1 ]
console.log(list0) // [ 1, 2, 3, 4, 5 ] 元のまま

今度は右から折り畳むので acc.concat([item]) としている。つまり foldl とは逆に対象となる item を生成する配列の末尾に追加していく。

Haskell に移植

foldl 版の reverse を Haskell に移植:

list0 :: [Int]
list0 = [1,2,3,4,5]

list1 :: [Int]
list1 = reverse' list0


f :: [Int] -> Int -> [Int]
f acc item = item : acc

reverse' :: [Int] -> [Int]
reverse' xs = foldl f [] xs

main :: IO ()
main = putStrLn $ show list1

環境はこれ:

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 9.4.7

実行:

$ runghc main.hs
[5,4,3,2,1]

以上です。