这是将类型t的操作符转换为操作符的标准方法a->t吗?即,这是一个实现此功能的lib(fT如functionTransformer):
fT :: (t -> t -> t) -> (a -> t) -> (a -> t) -> (a -> t)
fT op f1 f2 = \x -> (f1 x) `op` (f2 x)
Run Code Online (Sandbox Code Playgroud)
(我们可以推广到fT :: (t1 -> t2 -> t) -> (t3 -> t1) -> (t3 -> t2) -> t3 -> t)
在学习Yesod时我问这个问题:在这个框架中,我们可以为字段添加验证条件,这要归功于checkBool.例如,我可以创建一个只接受大于100的值的字段:
smallIntField = checkBool (<= 100) "error: this entry has to be smaller than 100" intField
Run Code Online (Sandbox Code Playgroud)
感谢我的"函数变换器",我可以轻松地管理有界值:
($&&) = fT (&&)
boundedIntField = checkBool ((>= 0) $&& (<= 100)) "error: this entry has to be between 0 and 100" intField
Run Code Online (Sandbox Code Playgroud)
你真正想要的是liftA2或liftM2组合器(来自Control.Applicative或Control.Monad分别). 因为所有monad都是应用程序,所以它的liftM2工作方式是一样的liftA2,但是如果你想要或多或少的限制,这取决于你.使用monadic实现也会强制对参数进行评估,这是无法保证的liftA2.
你可以用它作为
(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool
(<&&>) = liftA2 (&&)
Run Code Online (Sandbox Code Playgroud)
对于像(>= 0)或者这样的函数(<= 100),Applicative f => f得到专门的(Ord a, Num a) => (->) a,所以类型签名就是
(<&&>) :: (Ord a, Num a) => (a -> Bool) -> (a -> Bool) -> (a -> Bool)
Run Code Online (Sandbox Code Playgroud)
所以你可以写一些像
between :: Int -> Int -> Int -> Bool
between lower upper = (lower <=) <&&> (<= upper)
Run Code Online (Sandbox Code Playgroud)
如果你定义了<||> = liftM2 (||)那么你甚至可以做一些更复杂的事情
between 0 100 <||> between 200 400 <||> (>= 1000) :: Int -> Bool
Run Code Online (Sandbox Code Playgroud)
哪个会检查数字是否是[0, 100] U [200, 400] U [1000, inf)我们用set notation写的这个元素(U是set union).