简体   繁体   English

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

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

I'm trying to create an instance for bind operator (>>=) to the custom type ST a我正在尝试为自定义类型ST a的绑定运算符(>>=)创建一个实例

I found this way to do it but I don't like that hardcoded 0 .我找到了这种方法,但我不喜欢硬编码的0

Is there any way to implement it without having the hardcoded 0 and respecting the type of the function?有没有办法在没有硬编码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))

I often find it easier to follow such code with a certain type of a pseudocode rewrite, like this: starting with the我经常发现用某种类型的伪代码重写更容易遵循这样的代码,就像这样:从

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

we get to the我们到达

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

which expresses the same thing exactly.这完全表达了同样的事情。 It is now a kind of a definition through an interaction law that it must follow.它现在是一种必须遵循的相互作用定律的定义 This allows me to ignore the "noise"/wrapping around the essential stuff.这让我可以忽略“噪音”/围绕重要的东西。

Similarly, then, we have类似地,那么,我们有

      (>>=) :: 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

because now we have an Int in sight (ie in scope), n , that will get provided to us when the combined computation s >>= f will "run".因为现在我们看到了一个Int (即在范围内) n它将在组合计算s >>= f将“运行”时提供给我们。 I mean, when it will runState .我的意思是,它什么时候会runState

Of course nothing actually runs until called upon from main .当然,除非从main调用,否则实际上什么都不会运行。 But it can be a helpful metaphor to hold in mind.但记住它可能是一个有用的比喻。

The way we've defined it is both the easiest and the most general, which is usually the way to go.我们定义它的方式是最简单也是最通用的,通常是go的方式。 There are more ways to make the types fit though.不过,还有更多方法可以使类型适合。

One is to use n twice, in the input to the second runState as well, but this will leave the i hanging unused.一种是使用n两次,在第二个runState的输入中也是如此,但这会使i未使用。

Another way is to flip the time arrow around w.r.t.另一种方法是围绕 w.r.t 翻转时间箭头。 the state passing, with state 通过,与

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

which is a bit weird to say the least.至少可以说有点奇怪。 s still runs first (as expected for the s >>= f combination) to produce the value a from which f creates the second computation stage, but the state is being passed around in the opposite direction. s仍然首先运行(正如s >>= f组合所预期的那样)以产生f创建第二个计算阶段的值a ,但 state 正在以相反的方向传递。

The most important thing to keep in mind is that your ST type is a wrapper around a function .要记住的最重要的事情是,您的ST类型是function的包装器。 What if you started your definition as (>>=) = \s -> \f -> S (\n ->... ) ?如果您以(>>=) = \s -> \f -> S (\n ->... )开始定义怎么办? It might be (ok, is) a bit silly to write separate lambdas for the s and f parameters there, but I did it to show that they're not really any different from the n parameter.在那里为sf参数编写单独的 lambda 表达式可能(好吧,是)有点愚蠢,但我这样做是为了表明它们与n参数没有任何不同。 You can use it in your definition of (>>=) .您可以在(>>=)的定义中使用它。

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

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