私は現在、ジョン・ヒューズ によって紙Programming with Arrowsを読んだし、私はすでに、セクション2.5で、最初の演習に困惑PG 20矢印のフィルタ関数を定義するにはどうすればよいですか?
に私達は私達の処分でArrow
とArrowChoice
型クラスを持っている、など関数のインスタンス、ストリーム関数[a] -> [b]
、およびKleisli
型を使用するモナディック関数a -> m b
が含まれます。
mapA
例が与えられた。
listcase :: [a] -> (Either() (a,[a]))
listcase [] = Left()
listcase (x:xs) = Right (x,xs)
helper :: (Bool,a) -> [a] -> Either (a,[a]) [a]
helper (True,x) y = Left (x,y)
helper (False,x) y = Right y
test :: Arrow a => (b -> Bool) -> a (b,c) ((Bool,b), c)
test p = first (arr p &&& arr id)
filterA :: Arrow a => (b -> Bool) -> a [b] [c]
filterA p = f >>> (g ||| (h >>> (j ||| (filterA p))))
where f = arr listcase
g = arr (const [])
h = test p >>> (uncurry helper)
j = (arr id *** (filterA p)) >>> (arr (uncurry (:)))
次のようにこの無益な試みの背後にある(ブルートフォース)根拠がある: で作ることには、2つの選択肢があります
mapA f = arr listcase >>>
arr (const []) ||| (f *** mapA >>> arr (uncurry (:)))
ここでの試みですfilterA
:listcase
はmap
のようになり、述語p
を適用した結果。 map
のように開始し、リストをチェックしてlistcase
を使用してEither値を返します。空のリストg
が適用されている場合は、|||
の右側のすべてが(a,[a])
タイプの値に適用され、それぞれhead
とtail
が含まれます。最初にh
関数が適用され、head
のまま述部が適用され、((Bool, head),tail)
の値が戻されます。これは(uncurry helper)
に渡され、は、Bool
の値に応じてhead
を保持するかどうかを決定します。結果はEither
という値で返され、選択方法(|||)
が適用されます。この値は(j ||| (filterA p))
に渡され、True
の場合、j
という語句がhead
とtail
を含むペアに適用されるようになります。 head
は、id
を使用してフィルタリングされ、filter p
は、tail
に適用されます。両方の結果はペアとして返されます。このペアは、arr (uncurry (:))
(map
など)を使用して調整されます。それ以外の場合はtail
がfilterA p
にのみ渡されます。
私はそれを作るようには難しいとは思っていませんが、私はかなり明白なものを欠いていると思います。
おかげで、よさそうです。私は、述語が投稿した直後にその述語が矢印であることに気付きましたが、あなたが指摘したように、それを変更しなかったので、私はそれを変更する必要はありませんでした。 '(不運なヘルパー)'を持ち上げないことは間違いでした。おそらく、最大の間違いは、 'filterA p'を' ArrowChoice'インスタンスにしていないことでした。この単純な変更により、私のコードは期待通りに動作することができますが、私はあなたの方が好きです。 – qubital