2017-02-27 19 views
0

には、以下の定型を避けるためにきれいな方法があります:レコードのデータ型定義を考えると安全なレコードフィールドクエリ

....

data Value = A{ name::String } | B{ name::String } | C{} 

は安全にname

getName :: Value -> Maybe String 
getName A{ name=x } = Just x 
getName B{ name=x } = Just x 
getName C{} = Nothing 
を返す関数を書きます

テンプレートハスケルでこれを行うことができることは分かっていますが、私はそれよりもクリーンなソリューションを探しています。おそらくGHCの拡張機能やそれ以外のものを見落としています。

+0

オーバーロードされたレコードフィールドを持つことができないため、これはバニラGHCでコンパイルできません。 – jkeuhlen

+0

@jkeuhlen No. 'name C'の' '*** Exception:レコードセレクタ名にマッチしない ''で失敗する部分関数' name :: Value - > String'を生成します。あなたは_different_データ型の共有フィールドを持つレコードを考えています。 – Alec

+0

データ型の定義にそのような定型文の必要性を導入します。代わりに 'data Value = AorB Bool String | C; getName(AorB _ x)= x; getName _ =何もなし ' – user2407038

答えて

4

lensTemplate Haskell helpers部分レコードフィールドに遭遇したときに正しいことをします。

{-# LANGUAGE TemplateHaskell #-} 


import Control.Applicative 
import Control.Lens 


data T = A { _name :: String } 
     | B { _name :: String } 
     | C 

makeLenses ''T 

これはABコンストラクタ内Stringを選択し、C場合には何もしませんnameと呼ばれるTraversal'を生成します。

ghci> :i name 
name :: Traversal' T String -- Defined at test.hs:11:1 

だから我々はMaybe名を引き出すためにControl.Lens.Foldから(previewために反転同義語である)the ^? operatorを使用することができます。

getName :: T -> Maybe String 
getName = (^? name) 

また、あなたのデータ型のコンストラクタのためのPrism' Sを作り、そして<|>を使用して一致するものの最初のいずれかを選択することができます。このバージョンは、コンストラクターのフィールドに異なる名前がある場合に便利ですが、コンストラクターを追加するときに抽出関数を更新することを忘れないでください。

makePrisms ''T 

getName' :: T -> Maybe String 
getName' t = t^?_A <|> t^?_B 

lensは非常に便利です!

0

なぜGADTを使用しないのですか?あなたがレコードだけを使うことに興味があるかどうかはわかりません。しかし、私はGADTが問題にきれいな解決策を提供することになりました。タイプを絞り込んでどのコンストラクタが有効であるかを制限できるからです。

{-# LANGUAGE GADTs #-} 

module Teste where 

data Value a where 
    A :: String -> Value String 
    B :: String -> Value String 
    C :: Value() 

name :: Value String -> String 
name (A s) = s 
name (B s) = s 

CValue()を生成しながらAB両方がValue String値を生成することに注意してください。関数を定義するとき

name :: Value String -> String 

具体的には、文字列を含む値だけを渡すことができます。したがって、AまたはB値のパターン一致のみが可能です。これはコード内にMaybeの必要性を避けるのに便利です。

+1

多分あなたは 'A :: {name :: String} - > Value String'と' B :: {name :: String} - > Value String'?こうすると、 'name :: Value String - > String'が自動的に生成されます。 – Alec

+0

@Alec:GHCバージョン8.0.1でこのような構文を試しましたが、うまくいきません。多分私は何かを欠いているでしょうか? –

+0

'-XGADTs'が有効になっていますか?もしそうなら、それはうまくいくはずです(そして、すでに多くのGHCバージョンを持っています)。 [this](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#generalised-algebraic-data-types-gadts)を参照してください。 – Alec