请考虑以下代码:
data A
data B
f :: A -> B
f = undefined
data T = TA A | TB B
data ListT = ListTA [A] | ListTB [B]
g :: [T] -> ListT
g l =
let
f' :: T -> B
f' (TA x) = f x
f' (TB x) = x
isA :: T -> Bool
isA TA{} = True
isA TB{} = False
in
case (all isA l) of
True -> ListTA (map (\(TA x) -> x) l)
False -> ListTB (map f' l)
main = pure ()
这背后的想法是我得到了A
或B
混合在一起的列表。我可以转换A -> B
但不能相反。根据此列表,我想制作A
的列表或B
的列表,前者如果我的所有原始列表元素都是A
s,后者如果至少一个是B
。
以上代码编译(我猜测会起作用)但是map (\(TA x) -> x) l
中的不完整模式匹配让我有点不舒服。这种不完全匹配只是我在这里做的必要吗?另外,我是否重新发明轮子,是否有一些能够概括我在这里所做的事情?
答案 0 :(得分:2)
我能想到的唯一方法就是
tryA :: [T] -> Maybe [A]
tryA [] = []
tryA (t:ts) =
case t of
TA x -> do xs <- tryA ts; return (x:xs)
TB _ -> Nothing
如果tryA
没有返回任何内容,请像以前一样map f' l
。
这样您只需一次通过all isA l
和map
,就可以避免不完整的模式。
答案 1 :(得分:2)
我按照这样的方式构建它:构建两个列表 - 一个充满A
个和一个充满B
个 - 这样可以构建A
列表可能会失败。可以构建一个实现此逻辑的Monoid
和foldMap
。
由于可能无法构建A
的列表,因此我们需要在Monoid
之上构建此Maybe
。我们想要的行为来自Maybe
&#39} Applicative
个实例:如果mappend
的任何一个参数都是Nothing
,那么整个事情就会失败,否则我们希望使用mappend
来合并这两个结果。这是组合Applicative
和Monoid
的一般方法。具体地:
newtype WrappedApplicative f a = Wrap { unWrap :: f a }
instance (Applicative f, Monoid m) => Monoid (WrappedApplicative f m) where
mempty = pure mempty
Wrap x `mappend` Wrap y = Wrap $ liftA2 mappend x y
我不知道这个newtype
是否在base
的某个地方。似乎那种东西会存在,但我无法找到它。
不用多说,Monoid
foldMap
我们将type Result = ([B], WrappedApplicative Maybe [A])
ping到:
a
我借用了(a, b)
's Monoid
instance,它与b
和Monoid
getAsOrToBs :: [Either A B] -> Either [A] [B]
getAsOrToBs = fromResult . foldMap toResult
where toResult (Left a) = ([aToB a], Wrap (Just [a]))
toResult (Right b) = ([b], Wrap Nothing)
fromResult (_, Wrap (Just as)) = Left as
fromResult (bs, Wrap Nothing) = Right bs
个实例并行委派。
foldr
或者,使用getAsOrToBs :: [Either A B] -> Either [A] [B]
getAsOrToBs = fromResult . foldr f ([], Just [])
where f (Left a) (bs, mas) = (aToB a : bs, fmap (a:) mas)
f (Right b) (bs, _) = (b:bs, Nothing)
fromResult (_, Just as) = Left as
fromResult (bs, Nothing) = Right bs
:
actionBarDrawerToggle.setDrawerIndicatorEnabled(false);
看,妈,没有部分功能!
答案 2 :(得分:1)
在得到其他答案的一些帮助之后,我将回答我自己的问题,为未来的观众带来好处。我相信g
最隐蔽的功能如下(并注意到我已经推广到Traversable
而不仅仅是列表)。
data ListT t = ListTA (t A) | ListTB (t B)
g :: (Traversable t) => t T -> ListT t
g l =
let
f2B :: T -> B
f2B (TA x) = f x
f2B (TB x) = x
f2A :: T -> Maybe A
f2A (TA x) = Just x
f2A (TB x) = Nothing
in
maybe (ListTB (fmap f2B l)) ListTA (traverse f2A l)
main = pure ()
在列表中,这应该只占用前导A
的数量空间,这是我认为的最小值。