2013-10-16 2 views
24

A、おそらくB、そして間違いなく1つのデータ構造を必要としています。私はこの事のための一般的なデータ型をハックした場合、それはおそらく次のようになります。このデータ構造"OneまたはBoth"の正規のhaskell型はありますか?

data OneOrBoth a b = A a | B b | AB a b 

maybeA :: OneOrBoth a b -> Maybe a 
maybeB :: OneOrBoth a b -> Maybe b 
eitherL :: OneOrBoth a b -> Either a b -- Prefers a 
eitherR :: OneOrBoth a b -> Either a b -- Prefers b 
hasBoth, hasExactlyOne, hasA, hasB :: OneOrBoth a b -> Bool 

ない名前がありますか?ハスケルで1つまたは両方の構造を扱う標準的な方法はありますか?

+0

なぜ2種類で停止:

module Some ( Some(), this, that, those, some, oror, orro, roro, roor, swap ) where import Control.Applicative ((<|>)) newtype Some a b = Some (Maybe a, Maybe b) deriving (Show, Eq) -- smart constructors this :: a -> Some a b this a = Some (Just a,Nothing) that :: b -> Some a b that b = Some (Nothing, Just b) those :: a -> b -> Some a b those a b = Some (Just a, Just b) -- catamorphism/smart deconstructor some :: (a -> r) -> (b -> r) -> (a -> b -> r) -> Some a b -> r some f _ _ (Some (Just a, Nothing)) = f a some _ g _ (Some (Nothing, Just b)) = g b some _ _ h (Some (Just a, Just b)) = h a b some _ _ _ _ = error "this case should be unreachable due to smart constructors" swap :: Some a b -> Some b a swap ~(Some ~(ma,mb)) = Some (mb,ma) -- combining operators oror, orro, roro, roor :: Some a b -> Some a b -> Some a b -- prefer the leftmost A and the leftmost B oror (Some (ma,mb)) (Some (ma',mb')) = Some (ma <|> ma', mb <|> mb') -- prefer the leftmost A and the rightmost B orro (Some (ma,mb)) (Some (ma',mb')) = Some (ma <|> ma', mb' <|> mb) -- prefer the rightmost A and the rightmost B roro = flip oror -- prefer the rightmost A and the leftmost B roor = flip orro 

組み合わせ演算子は楽しいですか! 3 4、 ...? :-) –

+12

「1 + A + B + A * B =(1 + A)*(1 + B)」または「(おそらくA、おそらくB ) '。 – rampion

答えて

42

Data.These

これは、いずれかの入力がある場合 組み合わせが定義されている2つの値の組み合わせを表現するのに有用であり得ます。代数的には、タイプ は、 の合計と積に簡単には含まれない(A + B + AB)を表します。Either A (B, Maybe A)のようなタイプは不明瞭で、 は使いにくいです。

+3

実際に正式ではありませんが、確かに自分のものよりも優れた選択ですが、このパッケージには多くの依存関係やエクストラが付属していますが、OPには有用でないかもしれません。 – bheklilr

+4

すべての場合。それはOPがこれをたくさん使っているように聞こえるが、もしこれが小さなものだったなら、私はprofunctors、mtl、semigroups等に依存したくないだろう。 – jozefg

+15

記事の後に付けられた固有名詞について話すのがいかに難しいかでうまくいく私は、「厳密」と「バイフォンター」を引っ張るという明確な利点を持つ[Acme.Whose](https://github.com/tel/acme-whose/)を書いた。それを使用しないでください。 –

6

Data.Theseが挙げられ、おそらく最良の選択ですが、私は自分自身をロールバックした場合、私のようにそれを行うだろうとされています:あなたが「0個、1個を望んでいた場合

import Control.Applicative ((<$>), (<*>)) 

type These a b = Either (Either a b) (a, b) 

maybeA :: These a b -> Maybe a 
maybeA (Left (Left a)) = Just a 
maybeA (Right (a, _)) = Just a 
maybeA _    = Nothing 

maybeB :: These a b -> Maybe b 
maybeB (Left (Right b)) = Just b 
maybeB (Right (_, b)) = Just b 
maybeB _    = Nothing 

eitherA :: These a b -> Either a b 
eitherA (Left (Left a)) = Left a 
eitherA (Right (a, _)) = Left a 
eitherA (Left (Right b)) = Right b 

eitherB :: These a b -> Either a b 
eitherB (Left (Right b)) = Right b 
eitherB (Right (_, b)) = Right b 
eitherB (Left (Left a)) = Left a 

hasBoth, hasJustA, hasJustB, hasA, hasB :: These a b -> Bool 

hasBoth (Right _) = True 
hasBoth _   = False 

hasJustA (Left (Left _)) = True 
hasJustA _    = False 

hasJustB (Left (Right _)) = True 
hasJustB _    = False 

hasA = (||) <$> hasBoth <*> hasJustA 
hasB = (||) <$> hasBoth <*> hasJustB 
5

、または両方の場合は1 + A + B + A*B = (1 + A) * (1 + B)または(Maybe A, Maybe B)となります。

あなたはnewtype(Maybe A, Maybe B)をラップして削除するには、スマートコンストラクタを使用してA + B + A*B = (1+A)*(1+B)-1を行うことができ(Nothing,Nothing)

λ this "red" `oror` that "blue" `oror` those "beige" "yellow" 
Some (Just "red",Just "blue") 
λ this "red" `orro` that "blue" `orro` those "beige" "yellow" 
Some (Just "red",Just "yellow") 
λ this "red" `roor` that "blue" `roor` those "beige" "yellow" 
Some (Just "beige",Just "blue") 
λ this "red" `roro` that "blue" `roro` those "beige" "yellow" 
Some (Just "beige",Just "yellow") 
+0

代数的因数分解法はうまくいきますが、実際にどのように単純に自分の和の型を転がすことよりも利点があるのか​​分かりません。 'newtype'の使用は基本的に同形であり、パターンマッチングはなくなりました。 – jozefg

関連する問題