我可以使用 pa_monad 来确保 η 扩展吗?

Posted

技术标签:

【中文标题】我可以使用 pa_monad 来确保 η 扩展吗?【英文标题】:Can I use pa_monad to ensure η-expansion? 【发布时间】:2014-07-01 04:43:46 【问题描述】:

我正在开发一个库,其中通常混合了几个状态单子。混入何种状态是先验未知的,但可能会在应用程序级别定义。因此,我的解决方案是开发 一个 具有可扩展隐藏状态的状态 monad。

(** ObjectStateMonad for composable State Monads *)
module ObjectStateMonad =
  struct
    (* A state monad yields tuple of a state-object and an observable value *)
    type ('a, 'b) monad = 'a -> ('a * 'b)

    (* usual bind, just more type parameters *)
    let bind : (('a, 'b) monad) -> ('b -> ('a, 'c) monad) -> ('a, 'c) monad = 
      fun m -> 
      fun f ->
      fun s ->
        let (st, obs) = m(s) in
        ( (f obs) st)

    (* run, as usual *)
    let run m a = m(a)

    type ('a, 'b) field =  field_get : 'a -> 'b ; field_set : 'a -> 'b -> 'a 

    (* get does not directly expose the state but requires a "getter" *)
    let get f = 
      let m : 'a -> ('a * 'b) = fun s -> (s, f.field_get s)
      in m

    (* put requires a "setter" function to modify the state *)
    let put f = 
      fun b ->
      let m : 'a -> ('a * unit) = fun s -> 
    let s2 : 'a = (f.field_set s b) in (s2, ()) 
      in m

    let yield a = fun s -> (s, a)

    let return = yield

    let rec repeat m = function
      | 0 -> m
      | n -> bind m (fun _ -> repeat m (n - 1))       

  end

我的实现使用行多态来实现可扩展性:

module FooState = struct
  open ObjectStateMonad

  type state_t = int

  class state_container = object
    val _foo : state_t = 0
    method get_foo = _foo
    method set_foo n = < _foo = n > 
  end

  let field =  field_get = (fun a -> (a#get_foo : state_t)) ; field_set = fun a b -> a#set_foo b 

  (* just an example operation *)
  let increment s = ( 
    perform n <-- get field ; 
    _ <-- put field (n+1); 
    return n 
  ) s

end

上面的模块演示了可组合性的工作原理:创建一个继承自所有相关状态容器的类,实例化该类并在它们上运行操作。

我的问题是,由于 OCaml 的多态性中的值限制,我不能在该状态单子上使用部分应用程序(这只是一个函数),因此我总是必须使应用程序显式(@ 中的参数 s 987654324@)。现在我正在使用 pa_monad 语法扩展,应该可以在每次执行时自动添加它,不是吗?

换句话说:我可以使用 pa_monad 对某些函数进行 η 扩展吗?

也感谢任何其他解决问题的方法。

【问题讨论】:

【参考方案1】:

你说得对 pa_monad;每当您在 perform 块中使用增量时,它将允许您省略 s 参数。例如,

open ObjectStateMonad
open FooState

let state, result =
  (perform
    _ <-- increment;
    _ <-- increment;
    a <-- increment;
    return a) (new state_container)
in
print_int state#get_foo ; print_char ':' ; print_int result

按预期打印出3:2

此外,您甚至不需要在增量定义中使用 s 参数。减少 η 的版本:

let increment = 
  perform n <-- get field ; 
  _ <-- put field (n+1); 
  return n

同样有效。

【讨论】:

以上是关于我可以使用 pa_monad 来确保 η 扩展吗?的主要内容,如果未能解决你的问题,请参考以下文章

如果使用与打字稿反应,我可以使用 tsx 扩展名来测试文件吗

Cast播放器示例使用扩展来确定流是不是是实时流,它可以使用标头吗?

我可以确保 Haskell 执行原子 IO 吗?

确保为特定队列扩展不超过 N 个实例

如何在离子中实现自定义日历?

PHP trait:是不是有适当的方法来确保使用 trait 的类扩展包含特定方法的超类?