12

Haskellで実装することで、レンズについて学ぼうとしています。view次のようにコンビネータを実装しました。

{-# LANGUAGE RankNTypes #-}

import Control.Applicative
import Data.Traversable

type Lens s a = Functor f => (a -> f a) -> s -> f s

view :: Lens s a -> s -> a
view lens = getConst . lens Const

ただし、 と組み合わせて使用​​しようとするとtraverse、次のエラー メッセージが表示されます。

Prelude> :load Lens.hs
[1 of 1] Compiling Main             ( Lens.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t view traverse

<interactive>:1:6:
    Could not deduce (Applicative f) arising from a use of ‘traverse’
    from the context (Traversable t)
      bound by the inferred type of it :: Traversable t => t a -> a
      at Top level
    or from (Functor f)
      bound by a type expected by the context:
                 Functor f => (a -> f a) -> t a -> f (t a)
      at <interactive>:1:1-13
    Possible fix:
      add (Applicative f) to the context of
        a type expected by the context:
          Functor f => (a -> f a) -> t a -> f (t a)
        or the inferred type of it :: Traversable t => t a -> a
    In the first argument of ‘view’, namely ‘traverse’
    In the expression: view traverse

残念ながら、このエラー メッセージがわかりません。それが何を意味し、どのように修正できるかを説明してください。

4

3 に答える 3

10

他の回答がすでに説明しているように、問題は、view任意の に対して機能するものを期待することですFunctor fが、そうであるtraverse場合にのみ機能します(fまたApplicative、適用できないファンクターがあります)。

では、 の型が引数を取らないようにするlensことで問題が解決されます (実際、 lens のほとんどの関数は Lens 型のシノニムを使用せず、常により弱いものを使用します)。関数については、ever のみを使用していることに注意してください。これが、型シグネチャを次のように変更できる理由です。viewRank2viewf ~ Const

view :: ((a -> Const a a) -> s -> Const a s) -> s -> a

実装は同じままでかまいませんが、以下viewでも動作するようになりましたtraverse:

view traverse :: (Traversable t, Monoid a) => t a -> a

Monoid余分な制約に注意してください。f ~ Const aを設定するtraverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)とインスタンスが必要になるため、この制約が表示されますApplicative (Const a)。ただし、そのインスタンスにはMonoid制約がaあります。traversable は空であるか、複数の要素を含む可能性があるため、 and が必要になるため、これも理にかなっていmemptyますmappend

于 2014-09-10T20:35:17.470 に答える
3

traverseこのタイプがあります:

traverse :: (Applicative f, Traversable t) => (x -> f y) -> t x -> f (t y)

f明示的な型定義で自由変数を作成するとLens、その定義は実際には

type Lens s a = forall f . Functor f => (a -> f a) -> s -> f s

そのため、任意の に対してview操作できる関数が必要ですが、 に対してのみ操作できます。 FunctortraverseApplicative

の定義を に変更Functorするだけでエラーを修正できますが、それがまさにここで達成したいことかどうかはわかりません。ApplicativeLens

于 2014-09-10T19:49:33.317 に答える
3

tl;dr - の定義によると、すべての s に対して機能しないためLens、 aを a にtraverseすることはできません。LenstraverseFunctor


あなたのタイプを見てみましょう:

λ :set -XRankNTypes 
λ :m +Control.Applicative Data.Traversable 
λ type Lens s a = Functor f => (a -> f a) -> s -> f s
λ :t traverse
traverse
  :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)

この時点で、 は、ある意味で、私たちのタイプtraverseよりも少し一般的であることがわかります。つまり、レンズが からのみ関数を取得できるところから関数を取得できます。Lensa -> f ba -> f a

その場合に限定しても問題ないので、

λ :t traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
  :: (Applicative f, Traversable t) => (a -> f a) -> t a -> f (t a)

これで、型変数を並べる唯一の方法なので、 if が である場合traverseLensでなければならないことは明らかです。Lens (t a) a

それでは、試してみましょう。

λ :t traverse :: Lens (t a) a

<interactive>:1:1:
    Could not deduce (Traversable t1) arising from a use of `traverse'
    from the context (Functor f)
      bound by the inferred type of
               it :: Functor f => (a -> f a) -> t a -> f (t a)
      at Top level
    or from (Functor f1)
      bound by an expression type signature:
                 Functor f1 => (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
      at <interactive>:1:1-24
    Possible fix:
      add (Traversable t1) to the context of
        an expression type signature:
          Functor f1 => (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
        or the inferred type of
           it :: Functor f => (a -> f a) -> t a -> f (t a)
    In the expression: traverse :: Lens (t a) a

おっと、それは気に入らなかった。ちょっと待って、traverse私たちの型を使用するためにtは beTraversableでなければならないので、その制限を追加しましょう。(「可能な修正」と同じように)提案:

λ :t traverse :: Traversable t => Lens (t a) a

<interactive>:1:1:
    Could not deduce (Applicative f1) arising from a use of `traverse'
    from the context (Functor f, Traversable t)
      bound by the inferred type of
               it :: (Functor f, Traversable t) => (a -> f a) -> t a -> f (t a)
      at Top level
    or from (Traversable t1, Functor f1)
      bound by an expression type signature:
                 (Traversable t1, Functor f1) =>
                 (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
      at <interactive>:1:1-41
    Possible fix:
      add (Applicative f1) to the context of
        an expression type signature:
          (Traversable t1, Functor f1) =>
          (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
        or the inferred type of
           it :: (Functor f, Traversable t) => (a -> f a) -> t a -> f (t a)
    In the expression: traverse :: Traversable t => Lens (t a) a

さて、ここでの問題は、それが (の定義から得られる) であると推測できないことfですApplicative(これも を使用する必要があります)。traverseFunctorLens

Applicative fただし、コンテキストに追加することはできません-fは隠されています。と言うとき、 はすべての sに対して機能する必要type Lens s a = Functor f => (a -> f a) -> s -> f sがあると言っています。Lens Functor

しかしtraverse、 である のサブセットに対してのみ機能しFunctorますApplicative。したがって、このようにのタイプは、 esで許可されてtraverseいるよりも具体的です。Lens

于 2014-09-10T19:53:41.110 に答える