Haskell/Arrows
Introduction
[編集]Arrow は Monads の一般化だと考えることができる。全てのMonadはArrowに変換することができるが、ArrowはMonadに変換できない場合がある。Arrow型を導入する目的はMonadを使う目的と同じであり、ライブラリ向けに標準的な型を用意することである。しかし、Arrow型はMonadより広範囲の概念をサポートする。Arrow型では、部分的に静的な計算(出力の一部が入力に依存しない計算)や、複数の引数を取る計算を表すことができる。Monadで上手くいくならMonadだけを使えばよいのだが、Monadが使えそうだが使えない対象に対しては、Arrowを使うべきかもしれない。
proc
とarrowの根
[編集]まずArrowを使った記法に馴れることから始めよう。ここでは、簡単のため、最もシンプルな関数を表すArrowと、小さなサンプルプログラムを書くことにする。
それではテキストエディタを立ち上げてHaskellファイルを書いてみよう。ファイル名は、toyArrows.hsとでもしておく。
{-# LANGUAGE Arrows #-}
import Control.Arrow (returnA)
idA :: a -> a
idA = proc a -> returnA -< a
plusOne :: Int -> Int
plusOne = proc a -> returnA -< (a+1)
これがあなたの定義したはじめてのArrowだ。1番目の例は、恒等関数をArrowで表現したものであり、2番目の例は、もう少し意味のあるArrowで、入力に1を加えて出力する計算を表現するArrowである。これを -XArrows のオプションをつけてGHCiで読み込んで、何が起こるか見てみよう。
% ghci -XArrows toyArrows.hs ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.4.1, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base-1.0 ... linking ... done. Compiling Main ( toyArrows.hs, interpreted ) Ok, modules loaded: Main. *Main> idA 3 3 *Main> idA "foo" "foo" *Main> plusOne 3 4 *Main> plusOne 100 101
ちゃんと動きました。今回出てきた記号は3つある。
- キーワード
proc
- Arrowの根
-<
- インポートした関数
returnA
さて、1を足すことができるようになったので、これから2倍難しいことをやってみよう。2を足すArrowを定義する。
plusOne = proc a -> returnA -< (a+1)
plusTwo = proc a -> plusOne -< (a+1)
簡単な方法は、上の例のように(a+1)をplusOne
Arrowに入力することである。
plusOne
の定義とplusTwo
の定義がにていることに注目して欲しい。同じパターン proc FOO -> SOME_ARROW -< (SOMETHING_WITH_FOO) が使われている。
演習 |
---|
|
do
記法
[編集]さて、上のplusTwo
の定義を見て読者はがっかりしたのではないか。なぜ、plusOne
を2回実行する定義になっていないのかと。ここでは、do
記法を導入して、そのような定義を行ってみる。
plusTwoBis =
proc a -> do b <- plusOne -< a
plusOne -< b
GHCiで実行する。
Prelude> :r Compiling Main ( toyArrows.hs, interpreted ) Ok, modules loaded: Main. *Main> plusTwoBis 5 7
この記法で、さらに長いArrowの列を定義することができる。
plusFive =
proc a -> do b <- plusOne -< a
c <- plusOne -< b
d <- plusOne -< c
e <- plusOne -< d
plusOne -< e
Monads and arrows
[編集]- FIXME: I'm no longer sure, but I believe the intention here was to show what the difference is having this proc notation instead to just a regular chain of dos