更新列表中包含的更新列表

时间:2011-12-29 12:11:03

标签: haskell

基本上我想实现一个包含可以更新的列表的元组(或任何适合我的问题的数据类型)。由于不变性而且下面的演示代码当然不起作用。这只是为了更好地说明我想要实现的目标。

我想知道有没有任何优雅的方法,数据类型(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 

3 个答案:

答案 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

second2third3可以是您的通用功能 为你需要的所有元组定义一次,或者它们可以是某种东西 使用有意义的名称,例如messagestimestamp。无论如何,这个 是一次写入,然后隐藏在库中的东西。

使用GHCi进行测试可获得所需的结果:

ghci> :main

("192.168.1.1",3455,(1234566,["first","aaa","bbbb","ccccc"])) 
["first","aaa","bbbb","ccccc"]