Cli*_*ton 8 refactoring haskell list pattern-matching
请考虑以下代码:
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 ()
Run Code Online (Sandbox Code Playgroud)
这背后的想法是我有一个As或Bs混合在一起的列表.我可以转换A -> B但不是相反.根据这个列表,我想要制作一个As列表或s列表B,前者如果我的所有原始列表元素都是As,后者如果至少有一个是a B.
上面的代码编译(我猜测会起作用)但是不完整的模式匹配map (\(TA x) -> x) l让我有点不舒服.这种不完全匹配只是我在这里做的必要吗?另外,我是否重新发明轮子,有什么能够概括我在这里所做的事情吗?
在获得其他答案的帮助后,我将回答我自己的问题,以造福未来的观众。我相信最简洁的函数如下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 ()
Run Code Online (Sandbox Code Playgroud)
在列表上,这应该只占用与前导 s 的数量成比例的空间A,我认为这是最小的。