如果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")

在第三和第四行做非常相同的,它们在更新给定类型的字符串。 有没有办法通过一个单一的一个,如更换这两条线。通过分配的类型的变量?

有帮助吗?

解决方案

不通过分配类型的变量,但通过执行现场更换:

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

此返回相同的ST作为它的参数,但与myString字段的值替换。这领域的不错的功能,你可以做到这一点,而不关心数据的构造是哪一种,只要它是一个使用myString数据构造的一个。

其他提示

您可以使用废料 - 您 - 样板这一点。

{-# 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"和每一个至Bool True

我更喜欢丹的解决方案,但在GHC(2010年Haskell的标准)模式警卫一个整洁的替代迈克尔的提案:

{-# LANGUAGE PatternGuards #-}
changeST :: SomeType -> SomeType
changeST x | X _ <- x = X True
           | Y _ <- x = Y newString
           | Z _ <- x = Z newString
  where    newString = "newString"

changeST的三个定义是彼此分开的,所以简单的答案是“否”。有,但是,至少有两种方法可以做到这一点。

一次

模式匹配的YZ两个构造:

您可以通过使您的模式匹配更普遍结合第二和第三个定义

changeST x = x { myString = "newString"}

此产生x的新版本,它是否是一个YZ,替换字符串构件。你必须这样做时要小心,虽然。如果您稍后重命名Z的字符串字段,例如,您将看到一个Z参数调用changeST时得到运行时模式匹配失败。

使用的情况下,表达

如果你把你的三个定义成一个,你可以在它们之间共享数据。

changeST :: SomeType -> SomeType
changeST x = case x of
    X _ -> X True
    Y _ -> Y newString
    Z _ -> Z newString
  where
    newString = "newString"
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top