Life Goes On

まあまあだけど楽しんでる方です

カリー化ふたたび

以前に書いたセミナーの振り返り(カリー化、部分適用、その他の話題 - Life Goes On)について、通勤電車でつらつら考えていて、小さいラムダ式と大きいラムダ式を区別するには、モナドなし/あり2つの Arrow を使えばいいんじゃないかと思いました。
つまりこんなコード。

g :: (Int, Int, Int) -> IO Int
g (a,b,x) = return (a*x+b)

g' :: (Int, Int) -> IO (Int -> Int)
g' (a,b) = return (\ x -> a*x+b)

g'' :: Int -> IO (Int -> Int -> Int)
g'' a = return (\ b x -> a*x+b)

g''' :: IO (Int -> Int -> Int -> Int)
g''' = return (\ a b x -> a*x+b)

main = do
    g0 <- g (3,5,7)
    print $ g0
    g1 <- g' (3,5)
    print $ g1 7
    g2 <- g'' 3
    print $ g2 5 7
    g3 <- g'''
    print $ g3 3 5 7
*Main> main
26
26
26
26

これなら g^^ と g^^^ も区別できるし、整合性はとれてるような気がします。そんな形式の話より、意味が大事なんだとは思うのですが。

あと、g^^^ を評価する実行エンジン(E)が何回か出てきますが、それぞれ数学的に違う型だというのは、理解しました。
でも実装に落ちると、いちばん外側の引数を固定化するという意味で、同じ実行エンジンが使える(逆に区別できない)ような気がします。
今度、聞いてみよう。

(それにしても我ながらしつこいなー)