【发布时间】:2019-11-21 04:55:28
【问题描述】:
我是 Haskell 的新手,需要帮助。我正在尝试构建一个必须以某种方式唯一的新数据类型,因此我决定使用 UUID 作为唯一标识符:
data MyType = MyType {
uuid :: UUID,
elements :: AnotherType
}
这样,我可以做到以下几点:
instance Eq MyType where
x == y = uuid x == uuid y
x /= y = not (x == y)
问题是(对我而言)所有已知的 UUID 生成器都会生成 IO UUID,但我需要在上面提到的纯代码中使用它。您能否建议是否有任何方法可以从 IO UUID 中提取 UUID,或者是否有更好的方法可以在 Haskell 中执行我需要的操作?谢谢。
更新
感谢所有伟大的建议和代码示例。从这里发布的内容来看,我可以说你不能破坏referential transparency,但是有一些聪明的方法可以在不破坏它的情况下解决问题,并且可能是最优化的方法,列在下面的答案中。
还有一种替代方法,我可以根据提供的使用 State Monad 的建议自行探索:
type M = State StdGen
type AnotherType = String
data MyType = MyType {
uuid :: UUID,
elements :: AnotherType
} deriving (Show)
mytype :: AnotherType -> M MyType
mytype x = do
gen <- get
let (val, gen') = random gen
put gen'
return $ MyType val x
main :: IO ()
main = do
state <- getStdGen
let (result, newState) = runState (mytype "Foo") state
putStrLn $ show result
let (result', newState') = runState (mytype "Bar") newState
setStdGen newState'
putStrLn $ show result'
不确定它是否是最优雅的实现,但它确实有效。
【问题讨论】:
-
简短回答:你不知道。您只需构建一个更大的
IO操作来计算结果。你从来没有真正从IO UUID中“退出”UUID。看到这个问题:How to get normal value from IO action in Haskell -
你明白 (1) 什么是引用透明,(2) Haskell 是一种引用透明的语言,(3) 你所要求的会违反引用透明吗?
-
是的,我明白了。顺便问一下,是否还有其他方法可以做我需要做的事情,即创建一个包含唯一标识符的数据类型,并根据该标识符为该数据类型创建一个 Eq 实例。
-
顺便说一下,对于
instance Eq部分,如果您只定义==,将使用与您所写内容匹配的/=的默认定义,因此您可以离开它出来。
标签: haskell