ZipList
Functor
とApplicative
インスタンス ( Control.Applicative ) が付属していますが、なぜAlternative
でしょうか?
- いい例はありませんか?
- 以下で提案されているものはどうですか?
- 欠陥がありますか?
- 無駄ですか?
- 他の合理的な可能性 (
Bool
2 つの方法でモノイドになることができるなど) はありますか?したがって、どちらもインスタンスであってはなりませんか?
「インスタンスの代替 ZipList」(最初にコードを見つけるための引用符付き) を検索したところ、ライブラリ、いくつかのチュートリアル、講義ノートしか見つかりませんでしたが、実際のインスタンスは見つかりませんでした。
マット・フェンウィックはZipList A
、 がモノイドになるのは が の場合だけだと言いましたA
(こちらを参照)。ただし、要素の型に関係なく、リストはモノイドです。
同じ質問に対するAndrewCによるこの他の回答Alternative
では、インスタンスがどのように見えるかについて説明しています。彼は言う
には 2 つの賢明な選択があります
Zip [1,3,4] <|> Zip [10,20,30,40]
。
Zip [1,3,4]
それは最初だから - 多分と一致するZip [10,20,30,40]
最長であるため -Zip []
破棄されることと一致します
Zip
基本的にはどこですかZipList
。
答えは であるべきだと思いますZip [1,3,4,40]
。インスタンスを見てみましょう:
instance Aternative Zip where
empty = Zip []
Zip xs <|> Zip ys = Zip (go xs ys) where
go [] ys = ys
go (x:xs) ys = x : go xs (drop 1 ys)
Zip a
型引数を知らずに生成できるa
のはだけZip [] :: Zip a
なので、 の選択肢はほとんどありませんempty
。空リストがモノイドの中立要素である場合、リスト連結を使用したくなるかもしれません。ただし、のせいでgo
はありません。最初の引数リストの 1 つのエントリを使用するたびに、2 番目の引数リストからも 1 つ削除します。したがって、一種のオーバーレイがあります。左の引数リストは、右の引数リストの先頭 (またはそのすべて) を隠します。(++)
drop 1
[ 1, 3, 4,40] [10,20,30,40] [ 1, 3, 4] [ 1, 3, 4]
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | | | | | |
[ 1, 3, 4] | [10,20,30,40] []| | | [ 1, 3, 4]
[10,20,30,40] [ 1, 3, 4] [ 1, 3, 4] []
ziplists の背後にある 1 つの直感はプロセスです。結果の有限または無限のストリームです。Applicative
zip するとき、インスタンスによって反映されるストリームを結合します。リストの最後に到達すると、ストリームはそれ以上の要素を生成しません。ここでAlternative
インスタンスが役に立ちます。デフォルトのプロセスが終了するとすぐに引き継ぐ、同時置換 (実際には代替) を指定できます。
たとえばfmap Just foo <|> pure Nothing
、ziplist のすべての要素をfoo
aにラップするように記述してJust
、Nothing
その後に進むことができます。結果の ziplist は無限であり、すべての (実際の) 値が使い果たされるとデフォルト値に戻ります。Zip
これはもちろん、コンストラクター内に無限リストを追加することにより、手動で行うことができます。それでも、上記はより洗練されており、コンストラクターの知識を前提としないため、コードの再利用性が高くなります。
要素の型に関する仮定は必要ありません (モノイド自体であるなど)。同時に、定義は自明ではありません ((<|>) = const
そうであるように)。最初の引数でのパターン マッチングによってリスト構造を利用します。
上記の の定義<|>
は連想的であり、空のリストは実際には空の要素です。我々は持っています
Zip [] <*> xs == fs <*> Zip [] == Zip [] -- 0*x = x*0 = 0
Zip [] <|> xs == xs <|> Zip [] == xs -- 0+x = x+0 = x
(fs <|> gs) <*> xs == fs <*> xs <|> gs <*> xs
fs <*> (xs <|> ys) == fs <*> xs <|> fs <*> ys
したがって、求めることができるすべての法則が満たされます (これは、リストの連結には当てはまりません)。
このインスタンスは、次のものと一致していますMaybe
。選択は左に偏っていますが、左の引数が値を生成できない場合、右の引数が引き継がれます。機能
zipToMaybe :: Zip a -> Maybe a
zipToMaybe (Zip []) = Nothing
zipToMaybe (Zip (x:_)) = Just x
maybeToZip :: Maybe a -> Zip a
maybeToZip Nothing = Zip []
maybeToZip (Just x) = Zip (repeat x)
は選択肢の射 (意味psi x <|> psi y = psi (x <|> y)
とpsi x <*> psi y = psi (x <*> y)
) です。
編集:私が推測するsome
/メソッドについてmany
some (Zip z) = Zip (map repeat z)
many (Zip z) = Zip (map repeat z ++ repeat [])