2

lens引数を持ち、 type の 2 つの適用効果をmconcat持つMaybeモノイドになる関数を実装しようとしています(->) r。おそらくいくつかの基本が欠けているので、この問題を分解するための助けをいただければ幸いです。

次のように、同じ引数を渡さないように「ユーザー」コードを書きたいと思います。

z pom root [(textFrom "groupId"), (textFrom "artifactId"), (textFrom "version")]

textFrom :: Text -> Document -> Lens' Document Element -> Maybe Text
textFrom name pom ln = listToMaybe $ pom ^.. ln ./ ell name . text

これが私が試したものです。レンズなしのコンセプト:

Prelude Data.Monoid Control.Applicative> let f a b = Just $ show (a+1) ++ b
Prelude Data.Monoid Control.Applicative> let z a b xs = mconcat $ ($ b) <$> ($ a) <$> xs
Prelude Data.Monoid Control.Applicative> z 3 "x" [f,f]
Just "4x4x"

レンズ付き:

z :: (forall f. Functor f, Monoid b)  => Document -> ((Element -> f Element) -> Document -> f Document) -> [Document -> ((Element -> f Element) -> Document -> f Document) -> b] -> b
z pom ln xs = mconcat $ ($ ln) <$> ($ pom) <$> xs

しかし、コンパイルに失敗します:

    Couldn't match expected type ‘[a0
                               -> Document
                               -> [Document
                                   -> ((Element -> f Element) -> Document -> f Document) -> b]
                               -> b]’
            with actual type ‘(Element -> f Element) -> Document -> f Document’
Relevant bindings include
  xs :: (Element -> f Element) -> Document -> f Document
    (bound at Main.hs:27:10)
  z :: (forall (f1 :: * -> *). Functor f1)
       -> Monoid b =>
          Document
          -> ((Element -> f Element) -> Document -> f Document)
          -> [Document
              -> ((Element -> f Element) -> Document -> f Document) -> b]
          -> b
    (bound at Main.hs:27:1)
Probable cause: ‘xs’ is applied to too few arguments
In the second argument of ‘(<$>)’, namely ‘xs’
In the second argument of ‘($)’, namely ‘($ ln) <$> ($ pom) <$> xs’
4

1 に答える 1

2

レンズをコンテナに保管すると問題が発生することがありますが、ALens'. 概念的にALens' Element Documentは とほぼ同じFunctor f => ((Element -> f Element) -> Document -> f Document)ですが、コンテナーに入れると問題が少なくなります。注意すべき重要なことは、各レンズはすべてFunctorの s で普遍的に認定されているため、元の署名は実際には次のようになるはずです (ただし、これは完全には機能しません)。

z :: (Monoid b)
  => Document
  -> (forall f. Functor f => (Element -> f Element) -> Document -> f Document)
  -> [Document -> (forall f. Functor f => (Element -> f Element) -> Document -> f Document) -> b]
  -> b

z使用して型を指定するALens'と、最終的には次のようになります (ライブラリを使用していると仮定しますlens。そうでない場合は、下部の注を参照してください)。

 z :: (Monoid b)
   => Document
   -> ALens' Element Document
   -> [Document -> ALens' Element Document -> b] 

この新しい署名により、指定した元の定義が機能します。

Monoid別のインスタンスを使用して、この定義を単純化できます。インスタンスは、結果の型をMonoid b => (a -> b) Monoid持つ関数を結合します。Monoid次に例を示します。

lengthSum :: [a] -> Sum Int
lengthSum xs = Sum (length xs)

λ> (lengthSum <> lengthSum) "abc"
Sum {getSum = 6}

(<>)methodはmappend、各関数を指定された引数に適用した結果です (したがって、本質的には と同じになりますlength "abc" + length "abc")。同様に、mconcat関数のリストの結果を結合します。これは、各関数が同じ型であり、結果の型が のインスタンスである限り、複数の引数を持つ関数にも適用されますMonoid

このインスタンスを使用して、次のように定義できます。

z pom ln xs = mconcat xs pom ln

この定義は、タイプのレンズ バージョンと非レンズ バージョンの両方で機能します。

ライブラリを使用していない場合は、次のlensように定義できるはずALens'です

newtype ALens s t a b = ALens
  { getLens :: forall f. Functor f => (a -> f b) -> s -> f t
  }
type ALens' s a = ALens s s a a
于 2014-12-08T15:59:12.203 に答える