2011-08-29 4 views
9

私は、van Laarhovenのisomorphism lensesの小さな例に興味があり、data BValue = BValue { π :: Float, σ :: Float, α :: Float } deriving Show(具体的にはget/set/modify関数)のようなデータ型に適用されます。前もって感謝します。同形レンズ

答えて

6

バンLaarhovenのポストから、Lensタイプは

data Lens a b = forall r . Lens (Iso a (b, r)) 

だから、我々の場合にはaBValueであり、我々は1つ以上の要素を取り出すいくつかのlenesesを構築したいです。例えば、πを選ぶレンズを作ってみましょう。

piLens :: Lens BValue Float 

だから、FloatBValueからレンズになるだろう

piLens = Lens (Iso {fw = piFwd, bw = piBwd}) 

レンズは2つのことを選び出す(ラベルパイトリプルで、すなわち最初の1、。):残留r(ここでは省略されているため、haskellに存在する型を明示的に指定する必要がないため)と同型性があります。同型写像は順方向関数と逆方向関数から構成されます。

piFwd :: BValue -> (Float, (Float, Float)) 
piFwd (BValue {pi, sigma, alpha}) = (pi, (sigma, alpha)) 

forward関数は、必要なコンポーネントを単離します。ここでの残差タイプは「残りの部分」、つまりシグマとアルファフロートのペアです。

piBwd :: (Float, (Float, Float)) -> BValue 
piBwd (pi, (sigma, alpha)) = BValue { pi = pi, sigma = sigma, alpha = alpha } 

backward機能は類似しています。

ここで、BValueのπ成分を操作するためのレンズを定義しました。

他の7つのレンズは類似しています。 (7つのレンズ:シグマとアルファを選び、可能なすべてのペアを選び(注文を無視して)、BValueをすべて取り出し、()を選んでください。

私が確信していることはわかりませんが、私が書いたfwとbwの機能があまりにも厳しいと少し気になります。わからない。

我々はまだ行われていません。

は、我々はまだpiLensが実際にレンズの法律を尊重していることを確認する必要があります。 van LaarhovenのLensの定義についての素敵なことは、同形法則を調べるだけでいいということです。彼のブログ記事では、レンズの法則が計算されています。

だから、私達の証明の義務は以下のとおりです。

  1. fw piLens . bw piLens = id
  2. bw piLens . fw piLens = id

どちらの証明がpiFwdpiBwdの定義と構成に関する法律から直接従ってください。

+2

最後の1つ:「BValue」の取得/設定/変更機能はありません。 get/set/modify関数は、すべての 'Lens a b'型に対して一度だけ定義されます。 (ブログ記事を参照)。残された唯一のことは、例えば、あなたのデータ型に合わせた特定のレンズに 'get'を適用することです。それで 'get piLens'は' BValue'のpiフィールドのゲッターです。 – Lambdageek

+0

'bv :: BValue'のように、与えられた型の特定の変数に対してこれらのアクセサーを使う方法は?レンズはタイプに適用されるので、そのタイプに属する変数のフィールドを 'getまたは' setすることが可能でなければなりません。 –

+0

@mindboundレンズと値の両方にget/set/modify関数を適用するだけです。 '' get piLens bv'または '' modify lens(+ 1.0)bv' – Lambdageek

2

をチェックしてください。これは、レコードタイプのレンズを実装しています。

このパッケージを説明するために、次の2つのデータ型の例を考えてみましょう。

import Data.Label 
import Prelude hiding ((.), id) 

data Person = Person 
{ _name :: String 
, _age :: Int 
, _isMale :: Bool 
, _place :: Place 
} 

data Place = Place 
{ _city 
, _country 
, _continent :: String 
} 

両方のデータ型は、すべてのラベルにアンダースコアを前に付けたレコード型です。この下線は、テンプレートハスケルコードがこれらのフィールドのレンズを取得するためのコードです。派生レンズは、この単純なワンライナーで行うことができます。

$(mkLabels [''Person, ''Place]) 

レンズが作成されますすべてのラベルについて。

この例を見てみましょう。この71歳の仲間、私の隣人は例として彼を使用して気にしなかった、ヤンと呼ばれる:私たちは月が本当に彼は我々が取得するには、Get関数を使用することができると主張ほど古いことを確認したい

jan :: Person 
jan = Person "Jan" 71 True (Place "Utrecht" "The Netherlands" "Europe") 

年齢は整数として計算されます。

hisAge :: Int 
hisAge = get age jan 

今はアムステルダムに移りたいと思っています。あなたの昔を過ごすにはどんな良い場所でしょうか。組成物を用いて、我々は、構造体の内部の深い街の値を変更することができます。

moveToAmsterdam :: Person -> Person 
moveToAmsterdam = set (city . place) "Amsterdam" 

そして今:(。)

ghci> moveToAmsterdam jan 
Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe") 

組成物はControl.Categoryモジュールの一部であるオペレータを使用して行われます。このモジュールをインポートして、Haskell Preludeからデフォルト(。)、id関数を隠すようにしてください。

関連する問題