如何将Haskell中的单子式校验改写为Applicative形式?
实现方案
你说的没错,两个校验逻辑不存在先后依赖,完全可以用Applicative实现,这里给出两种符合需求的写法:
方式1:组合校验谓词后单次调用ensure
利用(->) a的Applicative实例,把两个独立的谓词组合为同时满足的复合谓词,再调用你的ensure函数校验:
import Control.Applicative (liftA2) -- 等价于 ensure (\x -> x > 0 && x < 100) x let validated = ensure (liftA2 (&&) (>0) (<100)) x
这里liftA2 (&&)把两个Int -> Bool类型的谓词,组合为一个新的Int -> Bool谓词,仅当输入同时满足两个原始谓词时返回True,全程用Applicative接口完成组合,没有手动写lambda拼接条件。
方式2:保留两次ensure调用的结构
如果要和你原写法的两次ensure调用结构对齐,直接在Maybe Applicative上下文内组合两次校验结果即可:
let validated = const <$> ensure (>0) x <*> ensure (<100) x
这段代码的逻辑和原Monad写法完全等价:
- 只要任意一次ensure返回Nothing,整个表达式结果就是Nothing
- 两次校验都通过时,会返回
Just x,和原输出完全一致
补充说明
Applicative适用的核心前提就是多个计算逻辑之间没有依赖,你这里的两个范围校验刚好符合这个特征,不需要前一步的输出作为后一步的输入,所以完全可以用Applicative替换Monad写法,逻辑上没有任何差异。
内容的提问来源于stack exchange,提问作者Ulrich Schuster
相关产品推荐
相关产品推荐

