简体   繁体   English

如何以及何时使用 State 仿函数和 State 应用程序?

[英]How and when to use State functor and State applicative?

I've seen the Maybe and Either functor (and applicative) used in code and that made sense, but I have a hard time coming up with an example of the State functor and applicative.我已经看到了代码中使用的MaybeEither仿函数(和应用程序),这是有道理的,但是我很难State函数和应用程序的示例。 Maybe they are not very useful and only exist because the State monad requires a functor and an applicative?也许它们不是很有用,只是因为State monad 需要一个仿函数和一个应用程序而存在? There are plenty of explanations of their implementations out there but not any examples when they are used in code, so I'm looking for illustrations of how they might be useful on their own.那里有很多关于它们的实现的解释,但在代码中使用它们时没有任何示例,所以我正在寻找它们如何单独使用的说明。

I can think of a couple of examples off the top of my head.我能想到几个例子。

First, one common use for State is to manage a counter for the purpose of making some set of "identifiers" unique.首先, State的一个常见用途是管理计数器以使某些“标识符”集唯一。 So, the state itself is an Int , and the main primitive state operation is to retrieve the current value of the counter and increment it:因此, state 本身是一个Int ,主要的原语 state 操作是检索计数器的当前值并增加它:

-- the state
type S = Int

newInt :: State S Int
newInt = state (\s -> (s, s+1))

The functor instance is then a succinct way of using the same counter for different types of identifiers, such as term- and type-level variables in some language:仿函数实例是对不同类型的标识符使用相同计数器的简洁方式,例如某些语言中的术语和类型级变量:

type Prefix = String
data Var = Var Prefix Int
data TypeVar = TypeVar Prefix Int

where you generate fresh identifiers like so:在哪里生成新的标识符,如下所示:

newVar :: Prefix -> State S Var
newVar s = Var s <$> newInt

newTypeVar :: Prefix -> State S TypeVar
newTypeVar s = TypeVar s <$> newInt

The applicative instance is helpful for writing expressions constructed from such unique identifiers.应用实例有助于编写由此类唯一标识符构造的表达式。 For example, I've used this approach pretty frequently when writing type checkers, which will often construct types with fresh variables, like so:例如,我在编写类型检查器时经常使用这种方法,它通常会使用新变量构造类型,如下所示:

typeCheckAFunction = ...
    let freshFunctionType = ArrowType <$> newTypeVar <*> newTypeVar
    ...

Here, freshFunctionType is a new a -> b style type with fresh type variables a and b that can be passed along to a unification step.在这里, freshFunctionType是一个新a -> b样式类型,带有新的类型变量ab ,可以传递给统一步骤。

Second , another use of State is to manage a seed for random number generation.其次State的另一个用途是管理随机数生成的种子。 For example, if you want a low-quality but ultra-fast LCG generator for something, you can write:例如,如果你想要一个低质量但超快的 LCG 生成器,你可以这样写:

lcg :: Word32 -> Word32
lcg x = (a * x + c)
  where a = 1664525
        c = 1013904223

-- monad for random numbers
type L = State Word32

randWord32 :: L Word32
randWord32 = state $ \s -> let s' = lcg s in (s', s')

The functor instance can be used to modify the Word32 output using a pure conversion function:仿函数实例可用于使用纯转换 function 修改Word32 output:

randUniform :: L Double
randUniform = toUnit <$> randWord32
  where toUnit w = fromIntegral w / fromIntegral (maxBound `asTypeOf` w)

while the applicative instance can be used to write primitives that depend on multiple Word32 outputs:而应用实例可用于编写依赖于多个Word32输出的原语:

randUniform2 :: L (Double, Double)
randUniform2 = (,) <$> randUniform  <*> randUniform

and expressions that use your random numbers in a reasonably natural way:以及以合理自然的方式使用随机数的表达式:

-- area of a random triangle, say
a = areaOf <$> (Triangle <$> randUniform2 <*> randUniform2 <$> randUniform2)

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

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