「F#をまねる」をまねる

F# の |> 演算子がかっこよいので、Haskell で作ってみた。

infixl 0 |>
(|>) :: a -> (a -> b) -> b
a |> f = f a

以下のようにシェルのパイプのような感じで使う。

foo :: String
foo = [1..100]
   |> map (*2) 
   |> filter (\x -> x `mod` 6 == 0) 
   |> sum
   |> show
http://d.hatena.ne.jp/kazu-yamamoto/20110218/1297992233

Schemeでマクロを活用して真似てみる.

(define-syntax >>
  (syntax-rules ()
    ((_ value)
     value)
    ((_ value (proc args ...) expr ...)
     (>> ((cut proc args ... <...>) value) expr ...))))

(define-syntax >>*
  (syntax-rules ()
    ((_ value)
     value)
    ((_ value (proc args ...) expr ...)
     (>>* (call-with-values (lambda () value)
            (cut proc args ... <...>)) expr ...))))

名前は適当,>>*は多値対応版だけどGaucheでは遅くなってしまった.気にする所じゃなさそうだけど.
使い方は

(>> (iota 100) (filter odd?) (map (pa$ * 2)) (fold + 0))
; => 5000
(>> (iota 100) (filter odd?) (map (pa$ * 2)) (take <> 10))
; => (2 6 10 14 18 22 26 30 34 38)
(>>* (values 7 2) (quotient&remainder) (+))
; => 4


(追記6:46)
@dico_leque さんにGaucheではcall-with-valuesよりreceiveの方が少し速いと教わったので書いてみた.速くなった.Gaucheではreceiveの方がプリミティブでcall-with-valueはただの手続きとのこと.

(define-syntax >>+
  (syntax-rules ()
    ((_ value)
     value)
    ((_ value (proc args ...) expr ...)
     (receive vars value
       (>>+ (apply (cut proc args ... <...>) vars) expr ...)))))

名前はますます適当である.
Gauche 0.9.2 で計測.コード適当だけど受け渡し部分を計りたいんだからこれでいいよね?

;(time (dotimes (_ 100000) (>> 1 (+ 2) (+ 3) (+ 4) (+ 5) (+ 6) (+ 7))))
; real   0.231
; user   0.220
; sys    0.000
;(time (dotimes (_ 100000) (>>* 1 (+ 2) (+ 3) (+ 4) (+ 5) (+ 6) (+ 7))))
; real   0.395
; user   0.380
; sys    0.010
;(time (dotimes (_ 100000) (>>+ 1 (+ 2) (+ 3) (+ 4) (+ 5) (+ 6) (+ 7))))
; real   0.341
; user   0.330
; sys    0.000


(追記19:53)

(define-syntax $>
  (syntax-rules (=>)
    ((_ value)
     value)
    ((_ value => proc expr ...)
     ($> (proc value) expr ...))
    ((_ value (proc args ...) expr ...)
     ($> ((cut proc args ... <...>) value) expr ...))))
($> 3 => (^x (+ x x)) (- <> 1))
; => 5