uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

Haksellでwhileを定義する

Haskell WIkiの「IO Inside」に、

Haskell's ability to work with IO actions as with any other (functional and non-functional) values allows us to define control structures of arbitrary complexity. Try, for example, to define a control structure that repeats an action until it returns the 'False' result:

while :: IO Bool -> IO ()
while action = ???

Most programming languages don't allow you to define control structures at all, and those that do often require you to use a macro-expansion system. In Haskell, control structures are just trivial functions anyone can write.

(私訳)

HaskellのIOアクションは、(関数型か否かに関わらず、)他のどんな値とも同様に扱うことができ、任意の複雑な制御構造を定義することができます。試しに、値がFalseを返すまで繰り返す制御構造を定義しみてごらんなさい。

while :: IO Bool -> IO ()
while action = ???

多くのプログラミング言語では、制御構造を定義することが全くできないか、マクロ拡張システムを必要とします。Haskellでは、制御構造は誰もが書けるただの関数にすぎません。

とあるのでやってみた。conditionとactionを分けてみました。

import Data.IORef

while :: IO Bool -> IO a -> IO ()
while cond action = do
  c <- cond
  if (c) then do action
                 while cond action
  else return()

main :: IO ()
main = do
  i <- newIORef 0
  while (do { n<-readIORef i; return (n<10) }) (do
              n<-readIORef i
              modifyIORef i (+1)
              print $ "hello"++show n)


「制御構造」に見えるかな。
whileに与えるところでdoを使うのが違和感があるので、使わないようにするとこうなる。

import Data.IORef

while :: IO Bool -> IO a -> IO ()
while cond action = do
  c <- cond
  if (c) then do action
                 while cond action
  else return()

main :: IO ()
main = do
  i <- newIORef 0
  while (readIORef i >>= (\n -> return (n<10) )) (do
              n <- readIORef i
              print $ "hello"++show n
              modifyIORef i (+1))

Groovyならクロージャを渡すようなことで実現できますが、上ではクロージャを全く使ってないところが興味深いです。(lambda式は>>=に渡すために使っているだけ)。

whileに渡したりwhileから返されたりするIOの値に含まれるRealWorld値(モナドによって隠蔽されている)は、それを導くのに使った計算に紐付いて来ていて、そのRealWorld値がmainのdoの地でも受け渡されていることで、mainの結果の計算に関与することになり、mainから始まっている命令的実行に組み込まれるようになるのだな…というイメージがないと黒魔術としか思えないです。


RealWorldによる値の制御は、プログラム上の表記位置とは全く独立なGotoみたいなもの。
グレッグ・イーガンの「順列都市」に出てきた「塵理論」を思い出させる、、って誰か指摘してるかな。