私は現在、 JohnHughesによるProgrammingwith Arrowsの論文を読んでおり、セクション2.5の20ページの最初の演習ですでに困惑しています。
自由に使える型クラスと型クラス、および型を介した関数、流れ関数Arrow、モナディック関数のインスタンスがあります。ArrowChoice[a] -> [b]a -> m bKleisli
mapA例が示されました:
mapA f = arr listcase >>>
arr (const []) ||| (f *** mapA >>> arr (uncurry (:)))
これが試みです:
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つの選択肢があります:filterAlikelistcaseとmap、述語を適用した結果p。mapそれは、リストをチェックし、を使用してEither値を返すように開始しますlistcase。空のリストgが適用される場合、それ以外の場合は、の右側のすべてが、およびをそれぞれ含む|||タイプの値に適用されます。関数が最初に適用されます。これは、を保持しながら述語を適用し、タイプの値を返します。これはに渡され、値に応じて保持するかどうかを決定します。結果を次のように返します(a,[a])headtailhhead((Bool, head),tail)(uncurry helper)headBoolEither選択方法を適用できるように値を設定します(|||)。この値は次の選択肢に渡されます。つまり、保持されて(j ||| (filterA p))いる述語が、とを含むペアに適用されるようにします。に適用されている間、を使用してフィルタリングされます。両方の結果がペアとして返されます。次に、このペアはlikeを使用して調整されます。それ以外の場合は、が単独で渡されます。Truejheadtailheadidfilter ptailarr (uncurry (:))maptailfilterA p
私がそれを実現するのと同じくらい難しいとは思えませんが、私はかなり明白な何かを見逃していると思います。