2

考虑 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')
inject_snd Nothing _ = Nothing

replace_snd替换对的第二个元素,如果没有对,则返回 Nothing:

> replace_snd 30 (Just (1, 2))
Just (1,30)
> replace_snd 30 Nothing
Nothing

inject_snd替换第二个元素,如果没有替换则返回 Nothing:

> inject_snd (Just 30) (1, 2)
Just (1,30)
> inject_snd Nothing (1, 2)
Nothing

还要考虑它们的对称对应物replace_fstinject_fst它们作用于一对的第一个元素:

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_sndis just (mapM . const),因为Maybeis aMonad((,) a)is a Traversable

> (mapM . const) (Just 30) (1, 2)
Just (1,30)
> (mapM . const) Nothing (1, 2)
Nothing

其他三个功能是否有类似的紧凑等价物?

4

2 回答 2

3
import Control.Arrow

replaceSnd = fmap . second . const

或者fmap . fmap . const,它不需要Arrow导入......但我不喜欢(a,)仿函数,这不会扩展到replaceFst. 然而,它Arrow同样简单:

replaceFst = fmap . first . const

injects 有点尴尬,但仍然可以通过应用程序操作符部分轻松完成:

injectSnd y t = fmap (($ t) . second . const) y
injectFst y t = fmap (($ t) . first . const) y

同样,您可以替换secondfmap,但请不要。

这个也可以写

injectSnd = flip $ \t -> fmap $ ($ t) . second . const

当然,如果您可以随意翻转签名,则flip不需要:

injectSnd' :: (a, b) -> Maybe b -> Maybe (a, b)
injectSnd' t = fmap $ ($ t) . second . const
于 2021-04-17T11:20:13.267 回答
3

它们都可以以紧凑的方式重写。例如replace_fst(or replace_snd) 是 的特例fmap :: Functor f => (a -> b) -> f a -> f b

replace_fst :: Functor f => a -> f (a, b) -> f (a, b)
replace_fst c = fmap ((,) c . snd)

或者我们可以使用first :: Arrow a => a b c -> a (b, d) (c, d)

import Control.Arrow(first)

replace_fst :: Functor f => a -> f (a, b) -> f (a, b)
replace_fst c = fmap (first (const c))

或更紧凑:

import Control.Arrow(first)

replace_fst :: Functor f => a -> f (a, b) -> f (a, b)
replace_fst = fmap . first . const

例如:

Prelude Control.Arrow> replace_fst 0 Nothing
Nothing
Prelude Control.Arrow> replace_fst 0 (Just (1,2))
Just (0,2)

至于inject_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

因此,我们对where执行fmaping ,如果是 a ,我们将返回 a ,否则如果是 a ,则返回 a 。ccJust yJust (first (const y) x)cNothingNothing

例如:

Prelude Control.Arrow> inject_fst Nothing (1,2)
Nothing
Prelude Control.Arrow> inject_fst (Just 0) (1,2)
Just (0,2)

这些函数不仅适用于 a Maybe,而且适用于 list[]Tree

于 2021-04-17T11:21:54.683 回答