可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am just working through some simple exercises in haskell and was wondering if there was a point-free way of converting an if-then-else statement into a Maybe
type: Nothing
being returned if the condition is false, and Just
the input if the condition is true.
In short, given some:
maybeIf :: (a -> Bool) -> a -> Maybe a maybeIf cond a = if cond a then Just a else Nothing
Is there an implementation that is point-free with respect to a
? I've also been looking at a more concrete version, a -> Maybe a
, and feel like there may be an answer somewhere in Control.Arrow
. However, since Maybe
is a data type and if-else statements control data flow, I'm unsure if there is a clean way of doing it.
回答1:
You can import find
from Data.Foldable
and then it's quite simply:
import Data.Foldable(find) maybeIf cond = find cond . Just
The function find
is not complicated so you could quite easily define it yourself less generically, in terms of Maybe
, but it isn't actually so different from your own implementation of maybeIf
so you might not gain much, depending on why you wanted to do it.
回答2:
The main thing getting in the way of making that pointfree is the if
/then
/else
. You can define an if'
combinator, or you can use this generalized version that I define and use often:
ensure p x = x <$ guard (p x)
Standard tools give successive point-free versions as
ensure p = ap (<$) (guard . p) ensure = ap (<$) . (guard .)
though I really don't think either are better than the pointful version.
回答3:
If we choose a Church-encoding for Booleans…
truth :: Bool -> a -> a -> a truth True t f = t truth False t f = f
Then we can write a point-free maybeIf
in Applicative-style.
maybeIf :: (a -> Bool) -> a -> Maybe a maybeIf = liftA3 truth <*> pure Just <*> pure (pure Nothing)
Some intuitions…
Here is a rendering in PNG format of the above "intuitions", in case your installed fonts do not support the needed unicode characters.
So therefore:
liftA3 truth <*> pure Just <*> pure (pure Nothing) = liftA3 truth <$> id <*> pure Just <*> pure (pure Nothing) = \p -> truth <$> id p <*> (pure Just) p <*> (pure (pure Nothing)) p = \p -> truth <$> p <*> Just <*> pure Nothing = \p -> \a -> truth (p a) (Just a) ((pure Nothing) a) = \p -> \a -> truth (p a) (Just a) Nothing
回答4:
Following dfeuer's lead (and using Daniel Wagner's new name for this function),
import Data.Bool (bool) -- F T -- bool :: a -> a -> Bool -> a ensure :: (a -> Bool) -> a -> Maybe a ensure p x = bool (const Nothing) Just (p x) x ensure p = join (bool (const Nothing) Just . p) = bool (const Nothing) Just =<< p ensure = (bool (const Nothing) Just =<<)
join
is a monadic function, join :: Monad m => m (m a) -> m a
, but for functions it is simply
join k x = k x x (k =<< f) x = k (f x) x
join
is accepted as a replacement for W combinator in point-free code.
You only wanted it point-free with respect to the value argument, but it's easy to transform the equation with join
further (readability of the result is another issue altogether), as
= join ((bool (const Nothing) Just .) p) = (join . (bool (const Nothing) Just .)) p
Indeed,
#> (join . (bool (const Nothing) Just .)) even 3 Nothing #> (bool (const Nothing) Just =<<) even 4 Just 4