gpt4 book ai didi

haskell - 在 Haskell 中以应用风格组合验证器

转载 作者:行者123 更新时间:2023-12-04 13:37:10 25 4
gpt4 key购买 nike

我对命令式编程有很好的掌握,但现在我自学了一个 Haskell。

我认为,我对 Monads、Functors 和 Applicatives 有很好的理论理解,但我需要一些练习。为了练习,我有时会从我目前的工作任务中带来一些东西。

而且我对以应用方式组合东西有点困惑

第一个问题

我有两个验证功能:

import Prelude hiding (even)

even :: Integer -> Maybe Integer
even x = if rem x 2 == 0 then Just x else Nothing

isSmall :: Integer -> Maybe Integer
isSmall x = if x < 10 then Just x else Nothing

现在我想要 validate :: Integer -> Maybe Integer建于 evenisSmall
我最好的解决方案是
validate a = isSmall a *> even a *> Just a

这不是免费的

我可以使用单子(monad)
validate x = do
even x
isSmall x
return x

但是,如果(我想)我只需要一个 Applicative,为什么要使用 Monad? (而且它仍然不是免费的)

这样做是更好(和更实用的方式)吗?

第二个问题

现在我有两个具有不同签名的验证器:
even = ...

greater :: (Integer, Integer) -> Maybe (Integer, Integer)
-- tuple's second element should be greater than the first
greater (a, b) = if a >= b then Nothing else Just (a, b)

我需要 validate :: (Integer, Integer) -> Maybe (Integer, Integer) , 尝试 greater在输入元组上,然后是 even在元组的第二个元素上。

validate' :: (Integer, Integer) -> Maybe Integer具有相同的逻辑,但返回元组的第二个元素。
validate  (a, b) = greater (a, b) *> even b *> Just (a, b)
validate' (a, b) = greater (a, b) *> even b *> Just b

但我想输入元组“流入” greater ,然后“流入”到 snd 的某种组合中和 even然后只有单个元素最终出现在 Just 中.

一个haskeller会做什么?

最佳答案

当您编写 a -> Maybe b 形式的验证器时你对整个类型比对 Maybe 更感兴趣适用的。类型a -> Maybe bMaybe 的 Kleisli 箭头单子(monad)。您可以制作一些工具来帮助处理这种类型。

对于第一个问题,您可以定义

(>*>) :: Applicative f => (t -> f a) -> (t -> f b) -> t -> f b
(f >*> g) x = f x *> g x

infixr 3 >*>

和写
validate = isSmall >*> even

你的第二个例子是
validate = even . snd >*> greater
validate' = even . snd >*> fmap snd . greater

它们以不同的顺序检查条件。如果您关心评估顺序,您可以定义另一个函数 <*< .

读者T

如果您使用类型 a -> Maybe b很多可能值得创建 newtype以便您可以添加自己的实例来执行您想要它执行的操作。 newtype已经存在;它是 ReaderT ,并且它的实例已经做了你想做的事情。
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

当您使用类型 r -> Maybe a作为验证器来验证和转换单个输入 rReaderT r Maybe 相同. Applicative instance for ReaderT 通过将它们的两个函数应用于同一输入,然后将它们与 <*> 组合在一起,将它们组合在一起。 :
instance (Applicative m) => Applicative (ReaderT r m) where
f <*> v = ReaderT $ \ r -> runReaderT f r <*> runReaderT v r
...
ReaderT<*>>*> 几乎完全相同从第一部分开始,但它不会丢弃第一个结果。 ReaderT*>>*> 完全相同从第一节开始。

ReaderT 方面你的例子变成
import Control.Monad.Trans.ReaderT

checkEven :: ReaderT Integer Maybe Integer
checkEven = ReaderT $ \x -> if rem x 2 == 0 then Just x else Nothing

checkSmall = ReaderT Integer Maybe Integer
checkSmall = ReaderT $ \x -> if x < 10 then Just x else Nothing

validate = checkSmall *> checkEven


checkGreater = ReaderT (Integer, Integer) Maybe (Integer, Integer)
checkGreater = ReaderT $ \(a, b) = if a >= b then Nothing else Just (a, b)

validate = checkGreater <* withReaderT snd checkEven
validate' = snd <$> validate

您使用其中之一 ReaderTx 上的验证器通过 runReaderT validate x

关于haskell - 在 Haskell 中以应用风格组合验证器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41237744/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com