-
18-09-2019 - |
题
如果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
的三个定义是彼此分开的,所以简单的答案是“否”。有,但是,至少有两种方法可以做到这一点。
模式匹配的Y
和Z
两个构造:
您可以通过使您的模式匹配更普遍结合第二和第三个定义
changeST x = x { myString = "newString"}
此产生x
的新版本,它是否是一个Y
或Z
,替换字符串构件。你必须这样做时要小心,虽然。如果您稍后重命名Z
的字符串字段,例如,您将看到一个Z
参数调用changeST时得到运行时模式匹配失败。
使用的情况下,表达
如果你把你的三个定义成一个,你可以在它们之间共享数据。
changeST :: SomeType -> SomeType
changeST x = case x of
X _ -> X True
Y _ -> Y newString
Z _ -> Z newString
where
newString = "newString"
不隶属于 StackOverflow