9

部分関数fと引数のリストが与えられた場合、が定義されているxsペアのリストを探しています。これは当然のことのように思えますが、これまでエレガントに表現できていませんでした。Maybe/Monad/Applicative/... エリアに役立つものがあるのだろうか? 以下は機能しますが、少し明示的なようです。(x, f(x))f

import Data.Maybe (mapMaybe)

graph :: (a -> b) -> [a] -> [(a, b)]
graph f = map (\x -> (x, f x))

liftMaybe :: (a, Maybe b) -> Maybe (a, b)
liftMaybe (x, Just y)  = Just (x, y)
liftMaybe (_, Nothing) = Nothing

partialgraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialgraph f = mapMaybe liftMaybe . graph f

liftMaybe別の名前で存在しますか?これらのいくつかの次の再定式化を見つけました。

import Control.Monad (ap)

graph' :: (a -> b) -> [a] -> [(a, b)]
graph' = map . ap (,)

liftMaybe' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe' (a, mb) = do
    b <- mb
    return (a, b)

liftMaybe'' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe'' (a, mb) = fmap ((,) a) mb

liftMaybe''' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe''' = uncurry (fmap . (,))
4

3 に答える 3

12

最も簡単なアプローチは、おそらくリスト内包表記を使用することです。

partialGraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialGraph f xs = [(x, fx) | (x, Just fx) <- graph f xs]

これは、リスト内包表記におけるパターン マッチングの失敗セマンティクスを利用しています。パターン マッチが失敗した場合、そのリスト要素はスキップされます。1

例えば、

ghci> partialGraph (\x -> if even x then Just $ x `quot` 2 else Nothing) [1..10]
[(2,1),(4,2),(6,3),(8,4),(10,5)]

liftSnd :: Functor f => (a, f b) -> f (a,b)どこにも関数が定義されていないようです。uncurry $ fmap . (,)あなたが得ようとしているのと同じくらい簡潔です。

あなたが定義する場合

preservingF :: Functor f => (a -> f b) -> a -> f (a, b)
preservingF = liftA2 fmap (,)

次に、この関数を使用して定義できます

partialGraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialGraph = mapMaybe . preservingF

これは非常にエレガントですが、 の定義はpreservingF少し不透明です (特にインライン化する場合)。2


1これは単に計算 を生成するリストモナドの (少し疑わしい) fail(または完全に妥当な) です。mzero[]

2そして、あなたが見つけられなかったようliftMaybeに、私はpreservingF長い間見つけられませんでした。

于 2014-03-10T21:25:15.773 に答える
3

の最も単純な定義liftMaybe

import Data.Traversable (sequenceA)

liftMaybe :: (a, Maybe b) -> Maybe (a, b)
liftMaybe = sequenceA

のドキュメントはhttp://hackage.haskell.org/package/base/docs/Data-Traversable.htmlsequenceAにあります。

一般的な型シグネチャは ですsequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)が、この場合t(,) cfですMaybe

また、次のpartialgraphように表現することもできますtraverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)(これも からData.Traversable):

partialgraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialgraph f = mapMaybe $ \x -> traverse f (x, x)

または、もう少し無意味にしたい場合:

partialgraph f = mapMaybe (traverse f . join (,))

編集:この回答を書いたとき、必要なインスタンスTraversableFoldableインスタンスがGHC 7.6.3標準ライブラリで定義されていないことに気づきませんでした(ただし、GHC 7.8にはあります)。これらは @robx の厚意によるものです。

instance Foldable ((,) a) where
  foldr f y (u, x) = f x y

instance Traversable ((,) a) where
  traverse f (u, x) = (,) u <$> f x
于 2014-03-11T04:26:45.870 に答える