4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

HaskellAdvent Calendar 2023

Day 8

以前の記事で書いたHaskellの再帰関数をStateモナドを使ってちゃんと書き直してみる

Last updated at Posted at 2023-12-07

概要

Qiitaに初投稿した拙い記事の中でこんな再帰だけのHaskellのコードを書いていた。

    update n x y = do
                   -- (描画処理など)
                   update (n+1) (x+vx) (y+vy)
                   where
                       r = n * pi/180.0
                       vx = sin r
                       vy = cos r

問題の記事では、コードを再帰させることの意味を強調するためにあえてそうしたつもりだったが、こういう時は素直にStateモナドを使ったほうが分かりやすいはずなので、一応ちゃんと書き直してみる。
特に意味はない。

本記事は関数型言語の入門程度の知識を前提としています。

使用環境

Haskell (ghc 8.4.4)

簡単な使用法

いきなりStateモナド自体の実装から入る解説が多いので、自分のようなミジンコでも手っ取り早く使える方法を記載しておく。(いい加減な情報なのでちゃんと知りたい方は参考文献を参照するかググってください)

Stateモナドは内部に状態変数を持っておける仕組みで、State s a(sは状態変数の型、aは関数の戻り値の型)という形でデータ型を定義できる。
do構文などを使えば途中で状態変数を変更したりできる。
Stateが保有する関数の実体はs -> (a, s)という関数型なので、下記のように漸化式のような形で直接指定することができる。
使用する際にはControl.Monad.Stateのインポートが必要。

import Control.Monad.State

-- 値を後置インクリメントするState関数
increment :: State Int Int
increment = state $ \x -> (x, x + 1) -- xを返してx + 1を状態変数として持つ

この他に、現在の状態変数を返すget、状態変数を更新するput、状態変数に変更を加えずに戻り値を返却するreturnが定義されている。
実際にそれなりの長さの関数を書く場合は恐らくこちらを使用した方が柔軟に書ける。

increment = do
    x <- get
    put (x + 1) -- x自体は更新されない
    return x

修正後

だいぶ蛇足感がありますが…

import Control.Monad.State

type FrameData = (Int, Double, Double)

update :: State FrameData ()
update = do
    (n, x, y) <- get -- 状態変数を取得
    let r = fromIntegral n * pi / 180.0
        vx = sin r
        vy = cos r
    put (n + 1, x + vx, y + vy) -- ステートを更新

-- ループ部分
mainloop :: State FrameData ()
mainloop = forever $ do
    update
    -- 描画処理など

状態変数を先に拾ってくる必要がある為where句は使用できない(できないことはないが面倒)。
修正前のコードでは一度実行すると無限に再帰し続けるが、Stateモナド版ではupdate関数を呼び出すことでステップ実行が可能。
実行するときはrunState mainloop (0, 0.0, 0.0)などとすれば良い。

参考文献

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?