问题描述
我在代码中看到了 Maybe
和 Either
函子(和 applicative),这是有道理的,但是我很难想出一个 State
函子和应用。也许它们不是很有用,只是因为 State
monad 需要函子和应用程序而存在?关于它们的实现有很多解释,但在代码中使用它们时没有任何示例,因此我正在寻找有关它们如何单独使用的说明。
解决方法
我能想到几个例子。
首先, fileprivate func showTipIfNedded() {
let optionItemListVC = PopOverViewController(text: "qewlghsflgha;lgh;lkfgj")
optionItemListVC.modalPresentationStyle = .popover
optionItemListVC.view.backgroundColor = .red
if let popover = optionItemListVC.popoverPresentationController {
popover.sourceView = self.view
popover.permittedArrowDirections = .down
//popover.containerView?.backgroundColor = .red
guard let firstTab = tabBarController?.tabBar.items?[0].value(forKey: "view") as? UIView else { return }
popover.sourceRect = CGRect(x: firstTab.frame.midX,y: (self.tabBarController?.tabBar.frame.minY)!,width: 1,height: 1)
optionItemListVC.preferredContentSize = CGSize(width: optionItemListVC.lbl.frame.width,height: optionItemListVC.lbl.frame.height)
popover.delegate = self
}
self.present(optionItemListVC,animated: true,completion: nil)
}
的一个常见用途是管理计数器,以使某些“标识符”集变得唯一。因此,状态本身是一个 State
,主要的原始状态操作是检索计数器的当前值并将其递增:
Int
函子实例是对不同类型的标识符使用相同计数器的简洁方式,例如某些语言中的术语和类型级变量:
-- the state
type S = Int
newInt :: State S Int
newInt = state (\s -> (s,s+1))
在这里生成新的标识符,如下所示:
type Prefix = String
data Var = Var Prefix Int
data TypeVar = TypeVar Prefix Int
应用实例有助于编写由此类唯一标识符构造的表达式。例如,我在编写类型检查器时经常使用这种方法,它通常会使用新变量构造类型,如下所示:
newVar :: Prefix -> State S Var
newVar s = Var s <$> newInt
newTypeVar :: Prefix -> State S TypeVar
newTypeVar s = TypeVar s <$> newInt
这里,typeCheckAFunction = ...
let freshFunctionType = ArrowType <$> newTypeVar <*> newTypeVar
...
是一个新的 freshFunctionType
样式类型,带有可以传递到统一步骤的新鲜类型变量 a -> b
和 a
。
第二,b
的另一个用途是管理用于随机数生成的种子。例如,如果你想要一个低质量但超快的 LCG 生成器,你可以这样写:
State
函子实例可用于使用纯转换函数修改 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')
输出:
Word32
而 applicative 实例可用于编写依赖于多个 randUniform :: L Double
randUniform = toUnit <$> randWord32
where toUnit w = fromIntegral w / fromIntegral (maxBound `asTypeOf` w)
输出的原语:
Word32
以及以合理自然的方式使用随机数的表达式:
randUniform2 :: L (Double,Double)
randUniform2 = (,) <$> randUniform <*> randUniform