Write Yourself a Scheme in 48 Hours/Evaluation, Part 1の中に次に示す apply 関数が定義してあります。
apply 関数は (+ 1 2 3) のような関数のときに func:"+"、 args:[Number 1,Number 2,Number 3] として、argsにfuncを適用させるための関数です。
lookup func primitives で 文字列 func:"+" から適用する関数 numericBinop (+)を探して来ます。その関数を args:[Number 1,Number 2,Number 3] に適用させたい訳です。で、該当する関数が見つからなかったときは評価の結果として(Bool False)を返す。
apply :: String -> [LispVal] -> LispVal apply func args = maybe (Bool False) ($ args) $ lookup func primitives
maybe に渡される引数は以下の順序ですが apply 関数の中で使用されているmaybe関数は適用する関数とそれを適用されるデータの引数の位置が逆になっています。
> :i maybe maybe :: b -> -- Maybe a が Nothing のときに返すdefault値 (a -> b) -> -- Maybe a に適用する関数 Maybe a -> -- (a -> b)が適用される値 b -- 関数の返す値の型 > maybe 0 (+1) (Just 10) -- > 11 > maybe 0 (+1) Nothing -- > 0 > maybe 0 ($ 10) (Just (+1)) -- > 11
なんと! 適用する関数と適用される値を逆に書けるのです。
($ 10) はどうなっているのでしょう。
> :i $ ($) :: (a -> b) -> a -> b -- Defined in GHC.Base infixr 0 $ > :t ($ 10) -- > ($ 10) は(Num a)を引数にして b を返す関数が引数として、b を返す。 ($ 10) :: (Num a) => (a -> b) -> b > ($ [1..10]) (map (+1)) -- > [2,3,4,5,6,7,8,9,10,11] > ($ [1..10]) (map show) -- > ["1","2","3","4","5","6","7","8","9","10"] > ($ [1..10]) (map even) -- > [False,True,False,True,False,True,False,True,False,True] > ($ [1..10]) (foldl (+) 0) -- > 55 > ($ [1..10]) (foldl (*) 1) -- > 3628800
($) を使って関数を引数とする関数を作っているのです。
we apply it to the arguments using ($ args), an operator section of the function application operator.
引数の順序を入れ替えたapply関数を以下に示します。
apply :: String -> [LispVal] -> LispVal apply func args = maybe (Bool False) ($ args) $ lookup func primitives -- 順序を入れ替えたapply関数 apply :: String -> [LispVal] -> LispVal apply func args = maybe (Bool False) -- fromMaybe で Just を取る。 -- Nothing のときは(numericBinop (const)) (fromMaybe (numericBinop (const)) $ lookup func primitives) (Just args) -- こっちにはJustを付ける。
下段の定義でも正常に動作します。