PowerShellでfoldl
概要
PowerShellのパイプで流れてきたオブジェクト群をたたみこむ。
mapとfilter
Windows PowerShellは、その名の通りWindowsのシェルで、
.NETのオブジェクトがパイプラインで流れるという特徴がある。
PowerShellで気になっているところは、
パイプラインから流れてきたオブジェクトを
高階関数mapとfilterのようなもので処理することができること。
コマンドはそれぞれForeach-ObjectとWhere-Objectで、簡単なエイリアスは"%"と"?"。
PS C:\> 1, 2, 3 | % {$_ * 3} 3 6 9 PS C:\> 1, 2, 3, 4, 5 | ? {$_ % 2 -eq 1} 1 3 5
これらの実現に使われているのが、スクリプトブロックという機能。
{$_ * 3}の部分がそれ。
これはScriptBlock型をもつオブジェクトのリテラルで、
&演算子で好きなときに実行することができる。
foldl (reduce)
mapとfilterがあったら次はreduceだ!ということで、
foldlとreduce(reduceはHaskellでいうとfoldl1)をfunctionで実装してみた。
function Main { 2, 3, 4 | foldl {$_l * 100 + $_r} 1 2, 3, 4 | foldl {[String]$_l + "たす" + $_r} 1 2, 3, 4 | reduce {$_l * $_r} 1 | reduce {$_l * $_r} ($null | reduce {}) -eq $null } function foldl { Param ([ScriptBlock] $script, [Object] $init) begin { $_l = $init } process { $_r = $_ $_l = & $script } end { $_l } } function reduce { Param ([ScriptBlock] $script) begin { $isFirst = $true } process { if($isFirst) { $isFirst = $false $_l = $_ } else { $_r = $_ $_l = & $script } } end { $_l } } . Main
実行結果
1020304 1たす2たす3たす4 24 1 True
Main関数は必須ではないが
長いfoldl, reduceの定義よりも実行部分を先に持ってくるのに使える。
Foreach-Object, と違って変数が2つ必要なのでそれぞれ
$_l, $_rと名付けた。アンダースコアは穴が開いているイメージ。
reduceでパイプから何も流れてこなかった場合、結果は$nullになる。
fold"r"はスタックがいりそうなので、コレクションの使い方を調べないと。