haskell - 将类型 `t` 上的运算符转换为类型 `a->t` 上的运算符

标签 haskell

这是将类型 t 上的运算符转换为类型 a->t 上的运算符的标准方法吗?即,这是一个实现此功能的库吗(fTfunctionTransformer):

fT :: (t -> t -> t) -> (a -> t) -> (a -> t) -> (a -> t)
fT op f1 f2 = \x -> (f1 x) `op` (f2 x)

(我们可以推广到 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

感谢我的“函数转换器”,我可以通过以下方式轻松管理有界值:

($&&) = fT (&&)
boundedIntField = checkBool ((>= 0) $&& (<= 100)) "error: this entry has to be between 0 and 100" intField

最佳答案

您真正需要的是liftA2liftM2组合子(分别来自 Control.ApplicativeControl.Monad)。 liftM2将与 liftA2 一样工作因为所有的单子(monad)都是应用程序,但是如果你想或多或少地限制,这取决于你。使用 monadic 实现也会强制参数的求值顺序,liftA2 无法保证。 .

你可以把它当作

(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool
(<&&>) = liftA2 (&&)

对于像 (>= 0) 这样的函数或 (<= 100) , Applicative f => f专攻 (Ord a, Num a) => (->) a ,所以类型签名是

(<&&>) :: (Ord a, Num a) => (a -> Bool) -> (a -> Bool) -> (a -> Bool)

所以你可以写类似的东西

between :: Int -> Int -> Int -> Bool
between lower upper = (lower <=) <&&> (<= upper)

如果您定义了 <||> = liftM2 (||)那么你甚至可以做一些更复杂的事情,比如

between 0 100 <||> between 200 400 <||> (>= 1000) :: Int -> Bool

这将检查数字是否是 [0, 100] U [200, 400] U [1000, inf) 的元素如果我们用集合表示法写这个(U 是集合并集)。

关于haskell - 将类型 `t` 上的运算符转换为类型 `a->t` 上的运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29758493/

相关文章:

haskell - 是否可以在 Haskell 中递归定义列表?

haskell - Haskell 中的 OCaml 模块的等价物是什么?

Haskell 模式匹配 do 表达式编译器警告

haskell - 如何在 Haskell 中装饰一棵树

parsing - Monadic 解析函数珍珠 - 将多个解析器粘合在一起

xml - HXT:如何使用箭头的输出作为函数参数?

testing - 使 Test.QuickCheck.Batch 使用默认类型来测试列表函数

web-applications - [$parseRoutes|/Home GET|] 中使用了什么样的 Haskell 语法?

file - Haskell 中的二维数组处理

haskell - 防止无意中使用不同类型的类实例