有无点的方法可以将条件检查转换为 Maybe 类型的输入吗?
Is there a point-free way to convert a conditional check into a Maybe type of the input?
我只是在 haskell 中完成一些简单的练习,想知道是否有一种无需点的方法可以将 if-then-else 语句转换为 Maybe
类型:[=如果条件为假,则返回 12=],如果条件为真,则返回 Just
。
简而言之,给出一些:
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf cond a = if cond a then Just a else Nothing
是否有相对于 a
无意义的实现?我也一直在寻找一个更具体的版本,a -> Maybe a
,感觉 Control.Arrow
中可能有答案。但是,由于 Maybe
是一种数据类型,而 if-else 语句控制数据流,我不确定是否有一种干净的方法来做到这一点。
实现这一点的主要障碍是 if
/then
/else
。您可以定义一个 if'
组合器,或者您可以使用我定义和经常使用的这个通用版本:
ensure p x = x <$ guard (p x)
标准工具给出连续的 point-free 个版本作为
ensure p = ap (<$) (guard . p)
ensure = ap (<$) . (guard .)
虽然我真的不认为任何一个都比有针对性的版本更好。
如果我们为布尔值选择 Church-encoding...
truth :: Bool -> a -> a -> a
truth True t f = t
truth False t f = f
那么我们可以在Applicative-style.
中写一个point-freemaybeIf
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf = liftA3 truth <*> pure Just <*> pure (pure Nothing)
一些直觉……
f <$> m₁ <*> … <*> mₙ = \x -> f (m₁ x) … (mₙ x)
liftAₙ f <$> m₁ <*> … <*> mₙ = \x -> f <$> m₁ x <*> … <*> mₙ x
如果您安装的字体不支持所需的 unicode 字符,这里是上述 "intuitions" 的 PNG 格式渲染。
因此:
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
您可以从 Data.Foldable
导入 find
然后就很简单了:
import Data.Foldable(find)
maybeIf cond = find cond . Just
函数 find
并不复杂,因此您可以根据 Maybe
轻松地自己定义它,但它实际上与您自己实现的 [=] 并没有太大区别15=] 所以你可能不会收获太多,这取决于你为什么想这样做。
遵循 (并为此功能使用 Daniel Wagner 的新名称),
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
是一个单子函数,join :: Monad m => m (m a) -> m a
,但对于函数来说它只是
join k x = k x x
(k =<< f) x = k (f x) x
join
被接受为 point-free 代码中 W combinator 的替代品。
你只想要它 point-free 关于 value 参数,但是很容易用 join
进一步转换等式(结果的可读性完全是另一个问题),因为
= join ((bool (const Nothing) Just .) p)
= (join . (bool (const Nothing) Just .)) p
的确如此,
#> (join . (bool (const Nothing) Just .)) even 3
Nothing
#> (bool (const Nothing) Just =<<) even 4
Just 4
但我更希望在实际代码中看到 \p x -> listToMaybe [x | p x]
。
或者只是 \p x -> [x | p x]
,使用 Monad Comprehensions。 与 x <$ guard (p x)
相同,只是语法不同。
此函数在 Control.Monad.Plus 中定义并称为 partial
我只是在 haskell 中完成一些简单的练习,想知道是否有一种无需点的方法可以将 if-then-else 语句转换为 Maybe
类型:[=如果条件为假,则返回 12=],如果条件为真,则返回 Just
。
简而言之,给出一些:
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf cond a = if cond a then Just a else Nothing
是否有相对于 a
无意义的实现?我也一直在寻找一个更具体的版本,a -> Maybe a
,感觉 Control.Arrow
中可能有答案。但是,由于 Maybe
是一种数据类型,而 if-else 语句控制数据流,我不确定是否有一种干净的方法来做到这一点。
实现这一点的主要障碍是 if
/then
/else
。您可以定义一个 if'
组合器,或者您可以使用我定义和经常使用的这个通用版本:
ensure p x = x <$ guard (p x)
标准工具给出连续的 point-free 个版本作为
ensure p = ap (<$) (guard . p)
ensure = ap (<$) . (guard .)
虽然我真的不认为任何一个都比有针对性的版本更好。
如果我们为布尔值选择 Church-encoding...
truth :: Bool -> a -> a -> a
truth True t f = t
truth False t f = f
那么我们可以在Applicative-style.
中写一个point-freemaybeIf
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf = liftA3 truth <*> pure Just <*> pure (pure Nothing)
一些直觉……
f <$> m₁ <*> … <*> mₙ = \x -> f (m₁ x) … (mₙ x)
liftAₙ f <$> m₁ <*> … <*> mₙ = \x -> f <$> m₁ x <*> … <*> mₙ x
如果您安装的字体不支持所需的 unicode 字符,这里是上述 "intuitions" 的 PNG 格式渲染。
因此:
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
您可以从 Data.Foldable
导入 find
然后就很简单了:
import Data.Foldable(find)
maybeIf cond = find cond . Just
函数 find
并不复杂,因此您可以根据 Maybe
轻松地自己定义它,但它实际上与您自己实现的 [=] 并没有太大区别15=] 所以你可能不会收获太多,这取决于你为什么想这样做。
遵循
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
是一个单子函数,join :: Monad m => m (m a) -> m a
,但对于函数来说它只是
join k x = k x x
(k =<< f) x = k (f x) x
join
被接受为 point-free 代码中 W combinator 的替代品。
你只想要它 point-free 关于 value 参数,但是很容易用 join
进一步转换等式(结果的可读性完全是另一个问题),因为
= join ((bool (const Nothing) Just .) p)
= (join . (bool (const Nothing) Just .)) p
的确如此,
#> (join . (bool (const Nothing) Just .)) even 3
Nothing
#> (bool (const Nothing) Just =<<) even 4
Just 4
但我更希望在实际代码中看到 \p x -> listToMaybe [x | p x]
。
或者只是 \p x -> [x | p x]
,使用 Monad Comprehensions。 与 x <$ guard (p x)
相同,只是语法不同。
此函数在 Control.Monad.Plus 中定义并称为 partial