15

かなり自明です。型クラスを作成する必要があることは知っていmakeClassyますが、2つの間に違いはありません。

PS。両方のデフォルトの動作を説明するためのボーナスポイント。

4

3 に答える 3

3

普通

makeLensesタイプのフィールドごとに 1 つのトップレベルの optic を作成します。アンダースコア ( ) で始まるフィールドを探し、_そのフィールドに対して可能な限り一般的なオプティックを作成します。

  • 型に 1 つのコンストラクターと 1 つのフィールドがある場合、Iso.
  • 型に 1 つのコンストラクターと複数のフィールドがある場合、 many が得られますLens
  • 型に複数のコンストラクターがある場合、 many を取得しますTraversal

上品

makeClassyタイプのすべての光学系を含む単一のクラスを作成します。このバージョンは、タイプを別のより大きなタイプに簡単に埋め込んで、一種のサブタイピングを実現するために使用されます。Lensそして、Traversal光学系は上記のルールに従って作成されます (Isoはサブタイピングの動作を妨げるため除外されます)。

フィールドごとにクラス内の 1 つのメソッドに加えて、このクラスのインスタンスを他の型に簡単に派生させる追加のメソッドを取得します。他のすべてのメソッドには、最上位のメソッドに関してデフォルトのインスタンスがあります。

data T = MkT { _field1 :: Int, _field2 :: Char }

class HasT a where
  t :: Lens' a T
  field1 :: Lens' a Int
  field2 :: Lens' a Char

  field1 = t . field1
  field2 = t . field2

instance HasT T where
  t = id
  field1 f (MkT x y) = fmap (\x' -> MkT x' y) (f x)
  field2 f (MkT x y) = fmap (\y' -> MkT x y') (f y)

data U = MkU { _subt :: T, _field3 :: Bool }

instance HasT U where
  t f (MkU x y) = fmap (\x' -> MkU x' y) (f x)
  -- field1 and field2 automatically defined

これには、特定のタイプのすべてのレンズを簡単にエクスポート/インポートできるという追加の利点があります。import Module (HasT(..))

田畑

makeFields指定された名前のフィールドを持つすべてのタイプ間で再利用されることを目的として、フィールドごとに 1 つのクラスを作成します。これは、タイプ間で共有できないフィールド名を記録するための解決策です。

于 2014-08-30T22:33:13.703 に答える
3

免責事項: これは実際のコードでの実験に基づいています。プロジェクトを進めるのに十分な情報が得られましたが、より適切に文書化された回答を希望します。

data Stuff = Stuff {
    _foo
    _FooBar
    _stuffBaz
}

makeLenses

  • fooへのレンズアクセサーとして作成しますStuff
  • 作成しますfooBar(大文字の名前を小文字に変更します);

makeFields

  • bazクラスを作成しHasBazます。Stuffそのクラスのインスタンスを作成します。
于 2014-08-30T19:41:11.753 に答える