繁体   English   中英

Haskell 自定义类型的“绑定”实例

[英]Haskell instance of `bind` for a custom type

我正在尝试为自定义类型ST a的绑定运算符(>>=)创建一个实例

我找到了这种方法,但我不喜欢硬编码的0

有没有办法在没有硬编码0和尊重 function 的类型的情况下实现它?

newtype ST a = S (Int -> (a, Int))
    
-- This may be useful to implement ">>=" (bind), but it is not mandatory to use it
runState :: ST a -> Int -> (a, Int)
runState (S s) = s
        
instance Monad ST where
      return :: a -> ST a
      return x = S (\n -> (x, n))
       
      (>>=) :: ST a -> (a -> ST b) -> ST b
      s >>= f = f (fst (runState s 0))

我经常发现用某种类型的伪代码重写更容易遵循这样的代码,就像这样:从

instance Monad ST where
      return :: a -> ST a
      return x = S (\n -> (x, n))

我们到达

  runState (return x) n = (x, n)

这完全表达了同样的事情。 它现在是一种必须遵循的相互作用定律的定义 这让我可以忽略“噪音”/围绕重要的东西。

类似地,那么,我们有

      (>>=) :: ST a -> (a -> ST b) -> ST b
      s >>= f = -- f (fst (runState s 0))   -- nah, 0? what's that?
      -- 
      -- runState (s >>= f) n = runState (f a) i where 
      --                                   (a, i) = runState s n
      --
                S $       \ n ->       let (a, i) = runState s n in
                                runState (f a) i

因为现在我们看到了一个Int (即在范围内) n它将在组合计算s >>= f将“运行”时提供给我们。 我的意思是,它什么时候会runState

当然,除非从main调用,否则实际上什么都不会运行。 但记住它可能是一个有用的比喻。

我们定义它的方式是最简单也是最通用的,通常是go的方式。 不过,还有更多方法可以使类型适合。

一种是使用n两次,在第二个runState的输入中也是如此,但这会使i未使用。

另一种方法是围绕 w.r.t 翻转时间箭头。 state 通过,与

                S $       \ n ->       let (a, i2) = runState s i 
                                           (b, i ) = runState (f a) n
                                        in (b, i2)

至少可以说有点奇怪。 s仍然首先运行(正如s >>= f组合所预期的那样)以产生f创建第二个计算阶段的值a ,但 state 正在以相反的方向传递。

要记住的最重要的事情是,您的ST类型是function的包装器。 如果您以(>>=) = \s -> \f -> S (\n ->... )开始定义怎么办? 在那里为sf参数编写单独的 lambda 表达式可能(好吧,是)有点愚蠢,但我这样做是为了表明它们与n参数没有任何不同。 您可以在(>>=)的定义中使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM