从 [Maybe Bool] 中获取一个保证至少包含一个 Just 的 Bool
Obtaining a Bool out of [Maybe Bool] which is guaranteed to contain at least one Just
我有一个类型为 [Maybe SomeType]
的输入 list
和一个类型为 SomeType -> Bool
的谓词 p
,我想回答问题 "谓词 p
是否适用于输入中碰巧出现的所有 SomeType
?.
第一部分很简单:(map . fmap) p list
的类型是 [Maybe Bool]
。
一个重要的信息是我知道 length list >= 1
和 all isNothing list == False
都成立,所以 (map . fmap) p list
中必须至少有一个 Just True
。
但是如何从列表中取出一首单曲 Bool
?
我认为我可以利用折叠(例如通过 foldl
)和 Maybe
的 MonadPlus
实例,执行如下操作:
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromJust . foldl mplus mzero
但这并不完全正确,因为 mplus
return 是左操作数,如果它是 Just something
而不管 something
是什么,所以 allTrueOrNothing
将 return True
即使它的输入是 [Just True, Just False]
.
我完成任务的cleanest/most惯用方法是什么?
我看到我可以简单地 filter
输出 Nothing
,然后 and
一起输出 Just
,像这样:
allTrueOrNothing' :: [Maybe Bool] -> Bool
allTrueOrNothing' = all fromJust . filter (fmap not isNothing)
但我更想知道是否有办法让那些 Maybe Bool
表现得像 Monoid
知道其 Bool
内容。
这似乎有效:
> and . catMaybes $ [Just False, Nothing, Just False]
False
> and . catMaybes $ [Just False, Nothing, Just True]
False
> and . catMaybes $ [Just True, Nothing, Just True]
True
您可以使用 catMaybes
将列表转换为 [Bool]
,并使用 and
进行总结。
(请注意,这将 return True
列入全部 Nothing
列表,根据您的假设,这是“不可能”的情况。)
如果你绝对想使用幺半群,我想你可以这样做,但它有点麻烦。它将涉及将列表的每个元素包装在一些 newtype And = And (Maybe Bool)
中,然后定义相关的幺半群实例,然后 mconcat
ing everying,最后解包。
未经测试的代码:
newtype And = And (Maybe Bool)
instance Semigroup And where
And Nothing <> x = x
x <> And Nothing = x
And (Just a) <> And (Just b) = And (Just (a && b))
instance Monoid And where
mempty = Nothing
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromMaybe False . coerce . mconcat @And . coerce
我会直接使用 all
:
all . all :: (a -> Bool) -> [Maybe a] -> Bool
如果由于某种原因你必须有你描述的相位区别,那么你可以使用专业化 and = all id
:
all and :: [Maybe Bool] -> Bool
最干净的方式是and . catMaybes
。
但是您想以 &&
的方式使用知道其 Bool
内容的 Monoid。那是 All
:
> foldMap (fmap All) [Just True,Nothing,Just False]
Just (All {getAll = False})
> foldMap (fmap All) [Just True,Nothing,Just True]
Just (All {getAll = True})
我有一个类型为 [Maybe SomeType]
的输入 list
和一个类型为 SomeType -> Bool
的谓词 p
,我想回答问题 "谓词 p
是否适用于输入中碰巧出现的所有 SomeType
?.
第一部分很简单:(map . fmap) p list
的类型是 [Maybe Bool]
。
一个重要的信息是我知道 length list >= 1
和 all isNothing list == False
都成立,所以 (map . fmap) p list
中必须至少有一个 Just True
。
但是如何从列表中取出一首单曲 Bool
?
我认为我可以利用折叠(例如通过 foldl
)和 Maybe
的 MonadPlus
实例,执行如下操作:
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromJust . foldl mplus mzero
但这并不完全正确,因为 mplus
return 是左操作数,如果它是 Just something
而不管 something
是什么,所以 allTrueOrNothing
将 return True
即使它的输入是 [Just True, Just False]
.
我完成任务的cleanest/most惯用方法是什么?
我看到我可以简单地 filter
输出 Nothing
,然后 and
一起输出 Just
,像这样:
allTrueOrNothing' :: [Maybe Bool] -> Bool
allTrueOrNothing' = all fromJust . filter (fmap not isNothing)
但我更想知道是否有办法让那些 Maybe Bool
表现得像 Monoid
知道其 Bool
内容。
这似乎有效:
> and . catMaybes $ [Just False, Nothing, Just False]
False
> and . catMaybes $ [Just False, Nothing, Just True]
False
> and . catMaybes $ [Just True, Nothing, Just True]
True
您可以使用 catMaybes
将列表转换为 [Bool]
,并使用 and
进行总结。
(请注意,这将 return True
列入全部 Nothing
列表,根据您的假设,这是“不可能”的情况。)
如果你绝对想使用幺半群,我想你可以这样做,但它有点麻烦。它将涉及将列表的每个元素包装在一些 newtype And = And (Maybe Bool)
中,然后定义相关的幺半群实例,然后 mconcat
ing everying,最后解包。
未经测试的代码:
newtype And = And (Maybe Bool)
instance Semigroup And where
And Nothing <> x = x
x <> And Nothing = x
And (Just a) <> And (Just b) = And (Just (a && b))
instance Monoid And where
mempty = Nothing
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromMaybe False . coerce . mconcat @And . coerce
我会直接使用 all
:
all . all :: (a -> Bool) -> [Maybe a] -> Bool
如果由于某种原因你必须有你描述的相位区别,那么你可以使用专业化 and = all id
:
all and :: [Maybe Bool] -> Bool
最干净的方式是and . catMaybes
。
但是您想以 &&
的方式使用知道其 Bool
内容的 Monoid。那是 All
:
> foldMap (fmap All) [Just True,Nothing,Just False]
Just (All {getAll = False})
> foldMap (fmap All) [Just True,Nothing,Just True]
Just (All {getAll = True})