【问题标题】:How to modify a list value in a nested custom datatype?如何修改嵌套自定义数据类型中的列表值?
【发布时间】:2020-02-27 07:20:23
【问题描述】:

假设我创建了一个新的数据类型如下:

data Typex = Typex {
   level       :: Int,
   coordinate  :: (Int, Int),
   connections :: [(Int,(Int,Int),Double)]  -- edited to be a tuple
   } deriving Show

我想从使用[[TypeX]] 的上层修改连接。我的自定义类型是否需要嵌套循环、fmap 和仿函数实例,或者您有什么建议?

【问题讨论】:

  • Haskell 没有循环。您的类型不是参数多态的,因此也排除了 Functor 实例。那只剩下fmap,或者只是map
  • 是的,连接应该是一个三元组列表。将其编辑为原始问题
  • @MarkSeemann Haskell 通过带有(相互递归)工作函数的手动编码递归(嵌套)循环。您可能指的是专用循环构造,但即便如此,具有 n 连续生成器的列表推导表达 n-levels-deep 嵌套循环。 :)
  • @MarkSeemann 如果没有Functor 实例,为什么fmap 是一个选项?虽然我需要实例才能使用它。
  • 您可以在列表中使用fmap(或map)。

标签: list haskell nested


【解决方案1】:

你可能想要lenses

{-# LANGUAGE TemplateHaskell   #-}

import Control.Lens

data Typex = Typex
  { _level       :: Int
  , _coordinate  :: (Int, Int)
  , _connections :: [(Int,(Int,Int),Double)]
  } deriving Show
makeLenses ''Typex

main :: IO ()
main = print $ [[Typex 0 (0,0) []]
               ,[Typex 1 (1,1) [], Typex 1 (2,2) []]
               ,[]]
             & ix 1 . ix 0 . connections
                 %~ ((9,(9,9),pi):)

在此示例中,嵌套列表索引 (ix) 到中间元素的头部,其中Typex 值集中在connections 字段上,并且有元素 (9,(9,9),pi) 前置。结果:

[[Typex {_level = 0, _coordinate = (0,0), _connections = []}],[Typex {_level = 1, _coordinate = (1,1), _connections = [(9,(9,9),3.141592653589793)]},Typex {_level = 1, _coordinate = (2,2), _connections = []}],[]]

【讨论】:

  • 是的,似乎只是简单的列表推导不会削减它。您(或其他任何人)能否举个例子或提示我如何使用镜头来实现对我在问题中提到的索引的引用?我想我必须使用 Control.Lens.Indexed 中的一些东西,但仅此而已。
  • 看来你在那里问了一个完全独立的问题。不要使用“编辑问题”来提出新问题!我建议您回滚该更改并实际发布为一个新问题。
  • 当然。在同一个问题中添加这可能有点太多了。在这里做了一个新的:stackoverflow.com/questions/60545053/…
【解决方案2】:

首先,描述您希望如何修改单个连接。给它起个名字:

modConnection (i, (j, k), d) = (i + 42, (j*5, k), d)

要更新整个连接列表,请使用map

modConnections cons = map modConnection cons

要更新记录中的字段,请使用 Haskell 记录更新语法:

modTypeX :: TypeX -> TypeX
modTypeX tx = tx { connections = modConnections (connections tx) }

要更新这些记录的完整列表,请再次使用 map

modTypeXList txs = map modTypeX txs

最后,要更新这些列表的整个列表,请再次使用 map

modTypeXListList txs = map modTypeXList txs

当然,如果你不想给每个中间函数起名字,你也不必,你可以内联做所有事情:

modTypeXListList = map . map $ \tx -> tx { connections = map modConnection (connections tx) }

【讨论】:

  • 这看起来像是我能应付的。镜头方法可能也会起作用,但如果可能的话,我宁愿使用像这样更简单的东西。最终目标是拥有一个 [[Typex]] -> [[Typex]] 函数,该函数在每个 TypeX 中生成大量这些连接 3 元组,但其中的所有 Int 值取决于 [[Typex]] 的结构给定函数,同时保持其余值不变。
猜你喜欢
  • 1970-01-01
  • 2017-08-17
  • 2019-01-24
  • 2022-01-11
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多