15

OCaml で状態モナドを実装しようとしていました (演習として)。私の実装は次のようになります。

module type MONAD_BUILDER =
sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
end;;

module MonadBuilder = functor (M: MONAD_BUILDER) ->
struct
  let ( >>= ) = M.bind
  let return = M.return
end;;

module StateM = 
struct
  type 'a state = { state: 's . 's -> ('a * 's) }
  type 'a t = 'a state
  let return x = { state = fun s -> (x, s) }
  let bind m f = 
    let aux s = 
      let (x, s') = m.state s in
      (f x).state s'
    in { state = aux }
  let run m x = fst (m.state x)
end;;

ファンクタを使用して状態型をモジュールにラップするという考えが気に入らないので、レコード フィールドに存在型を選択しました。上記の実装は機能しますが、実装中に問題が発生しましgetStatesetState。私はそれらを次のように実装しようとしました:

let getState = { state = fun s -> (s, s) }

let setState s = { state = fun _ -> ((), s) }

'a -> ('a * 'a)と などの推論されたフィールド型'a -> (unit * 'a)は、宣言された型より一般的ではないため、これは機能しません's . 's -> ('a * 's)。なぜこれが起こっているのか理解していますが、レコードアプローチを使用してそれを機能させる別の方法があるかどうか疑問に思っていましたか?

ありがとう。

乾杯、アレックス

4

1 に答える 1

13

's. 's -> ('a * 's)ユニバーサルタイプです。ユニバーサルタイプの状態を実装するのは難しいでしょう...

モジュールを使用せずにそこに存在型をカプセル化する明確な方法はありません (存在型は抽象型の目的であるため)。

もちろん、代わりに状態タイプを公開することもできます。

type ('a,'s) state = { state : 's -> ('a * 's) } 

またはさらに短く、

type ('a,'s) state = 's -> 'a * 's

追加のパラメーターを使用すると、コードが実行されます。ただし、パラメーターはモナドによって処理されなければならないという事実に遭遇します。したがって、モナドを構築するときにそれを非表示にすることができます:

module Monad = MonadBuilder(struct
  include StateM
  type 'a t = ('a,myStateType) state
end)

または、モナドの設計を変更して、存在型に使用される追加の型パラメーターを組み込みます。

module type MONAD_BUILDER =
sig
  type ('a,'param) t
  val return : 'a -> ('a,'param) t
  val bind : ('a,'param) t -> ('a -> ('b,'param) t) -> ('b,'param) t
end;;
于 2011-05-01T00:17:24.953 に答える