在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):snowleopard/selective开源软件地址(OpenSource Url):https://github.com/snowleopard/selective开源编程语言(OpenSource Language):TeX 74.7%开源软件介绍(OpenSource Introduction):Selective applicative functorsThis is a library for selective applicative functors, or just selective functors for short, an abstraction between applicative functors and monads, introduced in this paper. What are selective functors?While you're encouraged to read the paper, here is a brief description of
the main idea. Consider the following new type class introduced between
class Applicative f => Selective f where
select :: f (Either a b) -> f (a -> b) -> f b
-- | An operator alias for 'select'.
(<*?) :: Selective f => f (Either a b) -> f (a -> b) -> f b
(<*?) = select
infixl 4 <*? Think of Note that you can write a function with this type signature using
selectA :: Applicative f => f (Either a b) -> f (a -> b) -> f b
selectA x f = (\e f -> either f id e) <$> x <*> f Any apS :: Selective f => f (a -> b) -> f a -> f b
apS f x = select (Left <$> f) ((&) <$> x) Here we wrap a given function The branch :: Selective f => f (Either a b) -> f (a -> c) -> f (b -> c) -> f c
branch = ... -- Try to figure out the implementation! Finally, any selectM :: Monad f => f (Either a b) -> f (a -> b) -> f b
selectM mx mf = do
x <- mx
case x of
Left a -> fmap ($a) mf
Right b -> pure b Selective functors are sufficient for implementing many conditional constructs,
which traditionally require the (more powerful) -- | Branch on a Boolean value, skipping unnecessary effects.
ifS :: Selective f => f Bool -> f a -> f a -> f a
ifS i t e = branch (bool (Right ()) (Left ()) <$> i) (const <$> t) (const <$> e)
-- | Conditionally perform an effect.
whenS :: Selective f => f Bool -> f () -> f ()
whenS x act = ifS x act (pure ())
-- | Keep checking an effectful condition while it holds.
whileS :: Selective f => f Bool -> f ()
whileS act = whenS act (whileS act)
-- | A lifted version of lazy Boolean OR.
(<||>) :: Selective f => f Bool -> f Bool -> f Bool
(<||>) a b = ifS a (pure True) b
-- | A lifted version of 'any'. Retains the short-circuiting behaviour.
anyS :: Selective f => (a -> f Bool) -> [a] -> f Bool
anyS p = foldr ((<||>) . p) (pure False)
-- | Return the first @Right@ value. If both are @Left@'s, accumulate errors.
orElse :: (Selective f, Semigroup e) => f (Either e a) -> f (Either e a) -> f (Either e a)
orElse x = select (Right <$> x) . fmap (\y e -> first (e <>) y) See more examples in src/Control/Selective.hs. Code written using selective combinators can be both statically analysed (by reporting all possible effects of a computation) and efficiently executed (by skipping unnecessary effects). LawsInstances of the
There are also a few useful theorems:
Note that there are no laws for selective application of a function to a pure
select (pure (Left x)) y = ($x) <$> y -- Pure-Left
select (pure (Right x)) y = pure x -- Pure-Right In particular, the following is allowed too: select (pure (Left x)) y = pure () -- when y :: f (a -> ())
select (pure (Right x)) y = const x <$> y We therefore allow If Static analysis of selective functorsLike applicative functors, selective functors can be analysed statically.
We can make the instance Monoid m => Selective (Const m) where
select = selectA Although we don't need the function The data Validation e a = Failure e | Success a deriving (Functor, Show)
instance Semigroup e => Applicative (Validation e) where
pure = Success
Failure e1 <*> Failure e2 = Failure (e1 <> e2)
Failure e1 <*> Success _ = Failure e1
Success _ <*> Failure e2 = Failure e2
Success f <*> Success a = Success (f a)
instance Semigroup e => Selective (Validation e) where
select (Success (Right b)) _ = Success b
select (Success (Left a)) f = Success ($a) <*> f
select (Failure e ) _ = Failure e Here, the last line is particularly interesting: unlike the Let's clarify this with an example. Here we define a function to
construct a type Radius = Int
type Width = Int
type Height = Int
data Shape = Circle Radius | Rectangle Width Height deriving Show
shape :: Selective f => f Bool -> f Radius -> f Width -> f Height -> f Shape
shape s r w h = ifS s (Circle <$> r) (Rectangle <$> w <*> h) We choose > shape (Success True) (Success 10) (Failure ["no width"]) (Failure ["no height"])
Success (Circle 10)
> shape (Success False) (Failure ["no radius"]) (Success 20) (Success 30)
Success (Rectangle 20 30)
> shape (Success False) (Failure ["no radius"]) (Success 20) (Failure ["no height"])
Failure ["no height"]
> shape (Success False) (Failure ["no radius"]) (Failure ["no width"]) (Failure ["no height"])
Failure ["no width","no height"]
> shape (Failure ["no choice"]) (Failure ["no radius"]) (Success 20) (Failure ["no height"])
Failure ["no choice"] In the last example, since we failed to parse which shape has been chosen, we do not report any subsequent errors. But it doesn't mean we are short-circuiting the validation. We will continue accumulating errors as soon as we get out of the opaque conditional, as demonstrated below. twoShapes :: Selective f => f Shape -> f Shape -> f (Shape, Shape)
twoShapes s1 s2 = (,) <$> s1 <*> s2
> s1 = shape (Failure ["no choice 1"]) (Failure ["no radius 1"]) (Success 20) (Failure ["no height 1"])
> s2 = shape (Success False) (Failure ["no radius 2"]) (Success 20) (Failure ["no height 2"])
> twoShapes s1 s2
Failure ["no choice 1","no height 2"] Do we still need monads?Yes! Here is what selective functors cannot do: Further reading
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论