5

次の単純なケースに対処するための template-haskell/いくつかのレンズ空想に関する現在の慣習がないことを確認しています。

data Person = Person {
  name :: String,
  ...
}

data Company = Company {
  name :: String,
  ...
}

現在、インポートを修飾することでグローバル名前空間の汚染を回避していますが、レコード アクセスがぎこちなくなります。

import Person as P

isFred :: Person -> Bool
isFred p = (P.name p) == "Fred"

レコードフィールドにアクセスするためのより良い方法はまだありますか?


同じ分野をカバーする別の質問への便利なリンクがあるため、@ Emmanuel Touzeryの回答を受け入れています。もう 1 つの質問は、「haskell 名前空間」で検索しても表示されません。他の回答には問題はありませんが、受け入れることができるのは 1 つだけです。

そこに記載されているソリューションでは、テンプレート Haskell、レンズ、型クラスなどを使用して、基本的に各フィールド「HasName」に対して単一の関数「name」を持つ 1 つの型クラスを作成します。各データ型は、独自の実装を持つそのクラスのインスタンスです。それから、私が完全には理解していないいくつかの魔法があり、さまざまなタイプを関与させることができます。

これが一体何なのか疑問に思っている Haskell 初心者にとっては、レコードは基本的に、タプルの 2 番目の要素を選択する通常の関数として実装されたフィールドセレクターを持つタプルだからです。これらのフィールド セレクター関数をエクスポートすると、それらはグローバル名前空間に配置され、遅かれ早かれ (通常はすぐに) 衝突が発生します。

そのため、(上記の例のように) インポートを修飾するか、衝突しない名前を考え出そうとします (名前にプレフィックスを付けて、最善を尽くします)。

レンズ関連は 2013 年の時点で大流行しており、フィールド セレクター / ゲッター + セッターなどの構成が可能です。レンズの基本的な考え方はそれほど複雑ではありませんが、実装は頭を悩ませています。


記録のために (ha!) 他の投稿の解決策はおそらく私が求めているものだと思いますが、それには大量の魔法 (レコードの名前空間を偽造するためだけに 5 つの拡張機能) が必要です。

4

3 に答える 3

7

一般的には 2 つのアプローチしかありませんが、残念ながらコミュニティではそれらについてのコンセズがありません。

  1. それらに対する関数を含むレコードを別のファイルに配置し、次のように完全なエイリアスで修飾して使用します。

    import qualified Data.Person as Person; import Data.Person (Person)
    
    isFred :: Person -> Bool
    isFred p = (Person.name p) == "Fred"
    

    このアプローチは、ファイルにクラスが 1 つだけ含まれる Java などの言語と同じと考えてください。

  2. フィールド名の前にレコードの名前を付けて、レコードを同じファイルに配置します。

    data Person = Person {
      personName :: String,
      personAge :: Int,
      ...
    }
    

いずれのレンズ ライブラリもこの問題に取り組みません。

于 2013-10-04T08:48:17.107 に答える