基本上我想实现一个包含可以更新的列表的元组(或任何适合我的问题的数据类型)。由于不变性而且下面的演示代码当然不起作用。这只是为了更好地说明我想要实现的目标。
我想知道有没有任何优雅的方法,数据类型(IOREfs?)或模块可以为我做,或者在这种情况下,我真的需要拆分整个元组,并用更新的元素重建它。
顺便说一句:直观地说,我希望至少只要测试没有打印,就不会评估列表msgs。
test = ("192.168.1.1", 3455, (1234566, msgs))
msgs = ["aaa", "bbbb", "ccccc"]
main = do
--print test
let msg_tmp = "first" : msgs
let msgs = msg_tmp
print msgs
print test
答案 0 :(得分:3)
正如其他人所说,应该有非常具体和重要的理由不以功能的方式做事。你的元组似乎不必要地复杂,但是你可以用这样的额外信息来创建一个新元素:
addMsg (a,b,(c,msgs)) msg = (a,b,(c,msg:msgs))
答案 1 :(得分:2)
正如您所说,Haskell使用不可变数据类型。有STRefs和IORefs可以做类似可变的事情,但是如果你正在学习Haskell,那么你想先得到不可改变的事情。
Haskell确实有记录访问者,但没有元组。如果你写这样的东西:
data MyRecord {
ipAddress :: String,
magicNumber :: Integer,
messages :: [String]
} deriving Show
然后您可以使用字段名称作为字段上的get函数。给定
test = MyRecord "192.168.1.1" 12345 ["aaaa", "bbbb", "cccc"]
然后你可以使用表达式“messges test”或IO monad:
来获取消息print $ messages test
您可以使用一些特殊的语法糖来创建新版本的“test”,如下所示:
test2 = test {magicNumber = 654321}
这将test2设置为test的副本,但使用不同的magicNumber字段除外。
所以你可以说:
test3 = test {messages = "first" : messages test}
我同意的是有点笨拙,但你实际上并不经常需要它。
对于Haskell的改进记录系统存在一些提议,其中上述语法糖实际上成为一个函数,但没有任何共识背后的共识。您应该在必要时编写自己的修饰符,例如
modifyMessages :: ([String] -> [String]) -> MyRecord -> MyRecord
modifyMessages = -- Left as an exercise for the student
然后您可以将您的示例实现为
test4 = modifyMessges ("first" :) test
答案 2 :(得分:1)
您是否考虑过使用lenses?如果您的目的是让程序员更轻松,更透明地更新元组,那么它们就能很好地满足要求。以下使用优秀的fclabels
包:
import Data.Label
import Control.Category
import Prelude hiding ((.))
test = ("192.168.1.1", 3455, (1234566, msgs))
msgs = ["aaa", "bbbb", "ccccc"]
append x = modify messages (x :)
main = do
let test' = append "first" test
print test'
print (get messages test')
second2 = lens (\(a,b) -> b) (\b (a,_) -> (a,b))
third3 = lens (\(a,b,c) -> c) (\c (a,b,_) -> (a,b,c))
messages = second2 . third3
second2
和third3
可以是您的通用功能
为你需要的所有元组定义一次,或者它们可以是某种东西
使用有意义的名称,例如messages
或timestamp
。无论如何,这个
是一次写入,然后隐藏在库中的东西。
使用GHCi进行测试可获得所需的结果:
ghci> :main
("192.168.1.1",3455,(1234566,["first","aaa","bbbb","ccccc"]))
["first","aaa","bbbb","ccccc"]