4

SomeType が次のように定義されている場合:

data SomeType = X {myBool :: Bool} 
                | Y {myString :: String} 
                | Z {myString :: String}

そして、次のように、彼のタイプに依存する任意の X を更新します。

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST (Y s) = (Y "newString")
changeST (Z s) = (Z "newString")

3 行目と 4 行目はまったく同じことを行い、指定された型の文字列を更新します。これらの 2 行を 1 行に置き換える方法はありますか。タイプを変数に割り当てることによって?

4

4 に答える 4

17

型を変数に代入するのではなく、フィールド置換を行います。

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST st = st { myString = "newString" }

これは引数と同じ st を返しますが、myStringフィールドの値は置き換えられます。myString. _

于 2009-12-09T16:10:22.310 に答える
7

これにはScrap-Your-Boilerplateを使用できます。

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics

data SomeType
  = X { myBool :: Bool }
  | Y { myString :: String }
  | Z { myString :: String }
  deriving (Data, Typeable)

changeST :: SomeType -> SomeType
changeST = everywhere (mkT (const True)) . everywhere (mkT (const "newString"))

これにより、構造内のchangeSTすべての内部が に変更され、すべてがに変更されます。String"newString"BoolTrue

于 2009-12-09T17:10:02.553 に答える
4

私はDanのソリューションを好みますが、GHCのパターンガード(Haskell 2010の標準)はMichaelの提案に代わる優れた方法です。

{-# LANGUAGE PatternGuards #-}
changeST :: SomeType -> SomeType
changeST x | X _ <- x = X True
           | Y _ <- x = Y newString
           | Z _ <- x = Z newString
  where    newString = "newString"
于 2009-12-09T18:07:18.030 に答える
3

の 3 つの定義はchangeST互いに独立しているため、短い答えは「いいえ」です。ただし、これを行うには少なくとも 2 つの方法があります。

YコンストラクタとZコンストラクタの両方を一度にパターン マッチします。

パターン マッチングをより一般的にすることで、2 番目と 3 番目の定義を組み合わせることができます。

changeST x = x { myString = "newString"}

これにより、 の新しいバージョンが作成xされYZ文字列メンバーが置き換えられます。ただし、これを行うときは注意が必要です。たとえば、後で の文字列フィールドの名前を変更するZと、引数を指定して changeST を呼び出すと、ランタイム パターン マッチ エラーが発生しZます。

ケース式を使用します。

3 つの定義を 1 つに結合すると、それらの間でデータを共有できます。

changeST :: SomeType -> SomeType
changeST x = case x of
    X _ -> X True
    Y _ -> Y newString
    Z _ -> Z newString
  where
    newString = "newString"
于 2009-12-09T16:44:15.183 に答える