在Haskell中,如何在存在Maybe值的情况下替换成对元素?
考虑Haskell中的这两个函数:在Haskell中,如何在存在Maybe值的情况下替换成对元素?,haskell,monads,traversable,Haskell,Monads,Traversable,考虑Haskell中的这两个函数: replace_snd :: b -> Maybe (a, b) -> Maybe (a, b) replace_snd y' (Just (x, y)) = Just (x, y') replace_snd _ Nothing = Nothing inject_snd :: Maybe b -> (a, b) -> Maybe (a, b) inject_snd (Just b') (a, b) = Just (a, b') inj
replace_snd :: b -> Maybe (a, b) -> Maybe (a, b)
replace_snd y' (Just (x, y)) = Just (x, y')
replace_snd _ Nothing = Nothing
inject_snd :: Maybe b -> (a, b) -> Maybe (a, b)
inject_snd (Just b') (a, b) = Just (a, b')
inject_snd Nothing _ = Nothing
replace\u snd
替换对中的第二个元素,如果没有对,则不返回任何内容:
> replace_snd 30 (Just (1, 2))
Just (1,30)
> replace_snd 30 Nothing
Nothing
inject\u snd
替换第二个元素,如果没有替换,则不返回任何内容:
> inject_snd (Just 30) (1, 2)
Just (1,30)
> inject_snd Nothing (1, 2)
Nothing
也考虑它们的对称对应符<代码> RePATIOFFST,<代码> CujTuffFST ,作用于一对的第一个元素:
replace_fst :: a -> Maybe (a, b) -> Maybe (a, b)
replace_fst x' (Just (x, y)) = Just (x', y)
replace_fst _ Nothing = Nothing
inject_fst :: Maybe a -> (a, b) -> Maybe (a, b)
inject_fst (Just a') (a, b) = Just (a', b)
inject_fst Nothing _ = Nothing
我的问题是:这四个函数中,哪一个可以使用内置函数(如一元运算符)编写得更紧凑?怎么做
例如,我意识到inject\u snd
只是(mapM.const)
,因为可能是单子,(,)a)
是可遍历的:
> (mapM . const) (Just 30) (1, 2)
Just (1,30)
> (mapM . const) Nothing (1, 2)
Nothing
其他三个功能是否有类似的紧凑等价物
import Control.Arrow
replaceSnd = fmap . second . const
或者fmap。fmap。const
,它不需要箭头
导入。。。但是我不喜欢(a,)
functor,这不会扩展到replaceFst
。然而,使用箭头
同样简单:
replaceFst = fmap . first . const
inject
s有点笨拙,但仍然可以通过应用程序操作符部分轻松完成:
injectSnd y t = fmap (($ t) . second . const) y
injectFst y t = fmap (($ t) . first . const) y
同样,您可以用fmap
替换second
,但请不要这样做
这也可以写出来
injectSnd = flip $ \t -> fmap $ ($ t) . second . const
当然,如果您同意翻转签名,则无需进行flip
:
injectSnd' :: (a, b) -> Maybe b -> Maybe (a, b)
injectSnd' t = fmap $ ($ t) . second . const
它们都可以以紧凑的方式重写。例如,replace\u fst
(或replace\u snd
)是以下情况的特例:
或更紧凑:
import Control.Arrow(first)
replace_fst :: Functor f => a -> f (a, b) -> f (a, b)
replace_fst = fmap . first . const
至于inject\u fst
,这是相同的,只是我们现在将fmap
放在第一项上,因此:
import Control.Arrow(first)
inject_fst :: Functor f => f a -> (a, b) -> f (a, b)
inject_fst c x = fmap (($ x) . first . const) c
因此,我们在c
上执行fmap
ing,其中,如果c
是Just y
,我们将返回Just(first(const y)x)
,否则如果c
是Nothing
则返回Nothing
例如:
Prelude Control.Arrow> replace_fst 0 Nothing
Nothing
Prelude Control.Arrow> replace_fst 0 (Just (1,2))
Just (0,2)
Prelude Control.Arrow> inject_fst Nothing (1,2)
Nothing
Prelude Control.Arrow> inject_fst (Just 0) (1,2)
Just (0,2)
这些功能不仅适用于可能
,而且适用于列表
[]
,树
,等等。感谢您快速而有用的回复<代码>fmap。fmap。常数=fmap。(顺便说一句,我个人很欣赏(a,)
函子,将其视为“用a
装饰的值”。我知道这有点像一场圣战。@d呃,那是作者
。我对(a,)
单子的问题,甚至对(a,)的问题
traversable,就是元组应该直观地表现对称,但事实并非如此。相比之下,没有人期望Writer
在其参数之间是对称的。感谢您快速而有用的回答!对箭头的概括似乎对您没有帮助。您可以从数据中使用首先。Bifunctor
而不是使用(,)
以外的双触发器。
import Control.Arrow(first)
inject_fst :: Functor f => f a -> (a, b) -> f (a, b)
inject_fst c x = fmap (($ x) . first . const) c
Prelude Control.Arrow> inject_fst Nothing (1,2)
Nothing
Prelude Control.Arrow> inject_fst (Just 0) (1,2)
Just (0,2)