Haskellにはレコードメンバーのドット表記はありません。各レコードメンバーに対して、コンパイラーはRecType - > FieldType型の同じ名前の関数を作成します。これは名前の競合につながります。これを回避する方法はありますか?つまり、同じフィールド名を持つ複数のレコードを持つにはどうすればいいですか?Haskellレコードの名前の競合
答えて
この問題を回避する別の方法は、lensパッケージを使用することです。それは、あなたがこのように使用することができますmakeFieldsテンプレートHaskellの機能、提供しています。あなたはTemplateHaskellとレンズを使用しない場合
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeSynonymInstances #-}
import Control.Lens
data A = A
{ _aText :: String
}
makeFields ''A -- Creates a lens x for each record accessor with the name _aX
data B = B
{ _bText :: Int
, _bValue :: Int
}
-- Creates a lens x for each record accessor with the name _bX
makeFields ''B
main = do
let a = A "hello"
let b = B 42 1
-- (^.) is a function of lens which accesses a field (text) of some value (a)
putStrLn $ "Text of a: " ++ a ^. text
putStrLn $ "Text of b: " ++ show (b ^. text)
を、あなたもTemplateHaskellを使用して自動化するどのようなレンズ手動で行うことができます。
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
data A = A
{ aText :: String
}
data B = B
{ bText :: Int
, bValue :: Int
}
-- A class for types a that have a "text" field of type t
class HasText a t | a -> t where
-- An accessor for the text value
text :: a -> t
-- Make our two types instances of those
instance HasText A String where text = aText
instance HasText B Int where text = bText
main = do
let a = A "hello"
let b = B 42 1
putStrLn $ "Text of a: " ++ text a
putStrLn $ "Text of b: " ++ show (text b)
しかし、私はレンズの学習をお勧めします。これは、フィールドの変更や設定など、多くのユーティリティも提供しています。
大規模なプロジェクトでは、それぞれの型を独自のモジュールに保ち、それぞれの型の名前空間アクセサにHaskellのモジュールシステムを使用することをお勧めします。
例えば、私はいくつかのタイプのモジュールA
でA
ている可能性があります:
-- A.hs
data A = A
{ field1 :: String
, field2 :: Double
}
...とモジュールB
で同じ名前のフィールドを持つ別のタイプB
:場合は、
-- B.hs
data B = B
{ field1 :: Char
, field2 :: Int
}
を私は他のモジュールで両方の型を使いたいC
私はそれらをインポートして、どのアクセサーを意味するのかを区別できます:
-- C.hs
import A as A
import B as B
f :: A -> B -> (Double, Int)
f a b = (A.field2 a, B.field2 b)
残念ながら、Haskellは同じモジュール内に複数の名前空間を定義する方法がありません。そうしないと、各タイプを別のモジュールに分割してこれを行う必要があります。
それは動作しますが、それは本当に醜いと冗長だと思う。 –
これは非常に扱いにくいです、時々私はHaskellがネストされたモジュールをサポートしたいと思っています... – MathematicalOrchid
@MathematicalOrchidそれはそれほど厄介ではありません。実際、このアプローチは他の言語では一般的です。たとえば、Javaでは、各タイプ(クラスまたはインタフェース)を別々のファイルに配置する必要があります。 –
GHC開発者は、今後この問題をどのように処理するか計画しているようです。 this blog postの最後に記載されている、this planを調べてください。
- 1. XML名前空間競合
Cf. http://stackoverflow.com/questions/5775068/modeling-domain-data-in-haskell/5777042#5777042 – luqui
http://stackoverflow.com/questions/6922437/ and: http://stackoverflow.com/questions/6677834/ –
これはGHCのReal Soon Nowで修正されるかもしれません。私はそのGSoCプロジェクト:D – jozefg