2011-01-02 25 views
4

実行時にデータを構築する可能性はありますか?私は "読み取り"機能のようなものだが、[(フィールド名、値)]に当てはまるものを意味する。だから私はこのようにそれを使用することができます実行時に関数またはデータを呼び出す

genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a 

::私はのような機能を持つようにしたいのは、私が

data Street = Street String 
data City = City String 
data ZipCode = ZipCode String 

data Address = Address { 
     street :: Street, 
     city :: City, 
     zipCode :: ZipCode 
} 

を持っているとしましょう

genericConstructor "Address" [("street", Street "Baker"), 
           ("city", City "London"), 
           ("zipCode", ZipCode "12345")] :: Address 

私は任意の定型的なコードをしたくありません、 Reflection API for Javaに似たものを探しています。 現在、Data.DataおよびData.Typeableモジュールを見ていますが、どのように達成できるかわかりません。

これの目的は、いくつかのデータ形式とhaskellデータ構造の間のバインディングを作成することです。

+0

なぜこれは別注タイプである必要がありますか?文字列を別の文字列にマップできるハッシュテーブルやData.Mapのようなものを使用しないのはなぜですか? –

+0

私はMapも使うと思っていましたが、私には、別の種類のデータを持つことができるときに、すべてのデータをStringとして保持することは非常に不満です。 Haskellのレコードシステムは、レンズモジュールを使用する場合には、作業するのがはるかに良いですが。 –

答えて

0

私はあなたのscemeの一つの問題は、

genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a 

すべての「引数」で同じ構築可能タイプでなければならないであろうということだと思います。そのため、あなたは私が行うにはどのように完全にはよく分からない

genericConstructor :: (DataConstructable a) => String -> [forall b. DataConstructable b => (String, b)] -> a 

の線に沿って何かが必要になり、私は認めなければなりません。

データフォーマット文字列のすべてを解析するだけでは簡単ではないでしょうか?

+0

タイプシグネチャ「データa =>文字列 - >(文字列、forall b。データb => b)」 - > aはImpredicativeTypesを必要としましたが、私のために働いていました。私は、このアプリケーションの正しい型シグニチャは 'forall a。 Data a => String - > [(String、String)] - >多分a'ですが、パーサーがより良いアプローチになると私は同意します。 –

+0

ImpredicativeTypesタイプが減価償却されているので、より安全な選択肢があると私は警告しました。 –

+0

現在ImpredicativeTypes AFAIKの計画的な置き換えはありません。私はそれに依存する新しいコードを書くつもりはありません。 –

2

ここには、あなたが求めているものに近いものがあります。

import Data.Data 
import Data.Dynamic 
import Data.Maybe 

data City = City String deriving (Data, Typeable, Show, Eq) 
data Street = Street String deriving (Data, Typeable, Show, Eq) 

data Addr = Addr { 
    city :: City 
,street :: Street} deriving (Show, Eq, Data, Typeable) 

class Foo a where 
    genericConstr :: [(String,Dynamic)] -> a 

instance Foo Addr where 
    genericConstr = buildAddr 

lf ls nm = fromMaybe (error $ nm ++ " not found") (lookup nm ls >>= fromDynamic) 

buildAddr ls = Addr {city = lf ls "city", street = lf ls "street"} 

ロードこの、およびGHCiの中:

*Foo> genericConstr [("street", toDyn (Street "Baker")), ("city", toDyn (City "London"))] :: Addr 
Addr {city = City "London", street = Street "Baker"} 

これは、しかし、私には多くの作業のように思えます。 Haskellではすべての型をコンパイル時に解決する必要があるため、これは難しいことです。この場合、実行時情報(文字列「アドレス」など)を持つ型を作成しようとしています。これは可能ですが、すべてのステップでタイプシステムと戦うことになります。 Jasonとパーサーを使う方がおそらく良い方法だと私は同意します。

+0

GADTの「magic」を少し使って、依存型のエントリを持つ地図を作ることができます。 Dependent型は、Data.Dynamicよりも、このような点でかなり洗練されているようです。例えば、Intを "city"フィールドに入れようとしないなど静的に行うことができるからです。実際にリリースする準備はできていませんが、http://code.haskellのdarcsリポジトリに依存型の有限マップ型を実装しています。org /〜mokus/dependent-map誰かがこのようなものがどのように見えるか不思議であれば。同じディレクトリの別のdarcsリポジトリにある別の未リリースパッケージに依存します。 – mokus

関連する問題