【问题标题】:How to use iset with nested datatype and lenses?如何将 iset 与嵌套数据类型和镜头一起使用?
【发布时间】:2020-03-09 20:31:02
【问题描述】:

我无法让最后一个函数中的类型对齐。重点是设置与仅依赖于 3 元组索引的函数相关的所有价格双倍。元组中原来的 Double 值可以丢弃。

{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TupleSections #-}

import Control.Lens

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

initTypexLevel :: Int -> Int -> Int -> [Typex] 
initTypexLevel a b c = [ Typex a (x, y) [(0,(0,0),0.0)]
                       | x <- [0..b], y <- [0..c]
                       ]

buildNestedTypexs :: [(Int, Int)] -> [[Typex]]
buildNestedTypexs pts
     = setConnectionsx [ initTypexLevel i y y
                      | (i,(_,y)) <- zip [0..] pts
                      ]

setConnectionsx :: [[Typex]] -> [[Typex]]
setConnectionsx (x:rest@(y:_)) = map (connect y) x : setConnectionsx rest
  where connect :: [Typex] -> Typex -> Typex
        connect txs tx
          = tx & connections .~ (map ((tx ^. level) + 1, , 0.0) $ txs ^.. traverse.coordinate)
setConnectionsx lst = lst

setInitPrices  :: [[Typex]] -> [[Typex]]
setInitPrices  (x:rest) = map setIndexPrices x : setInitPrices  rest
  where setIndexPrices :: Typex -> Typex
        setIndexPrices tx =  n & connections .~ ??? -- using iset (?), set the price in every 3-tuple so that price = f (index of the 3-tuple) where f = i*2
setInitPrices  lst = lst

【问题讨论】:

    标签: haskell indices haskell-lens custom-data-type


    【解决方案1】:

    您可能正在寻找:

      where setIndexPrices :: Typex -> Typex
            setIndexPrices tx =  tx & connections .> traversed <. _3 .@~ f
            f i = 2 * fromIntegral i
    

    这里,.@~iset 的运算符版本,.&gt;&lt;. 是组合运算符 . 的变体,用于组合索引光学元件。

    如果您考虑更简单的未索引光学元件:

    connections . traverse . _3
    

    这个 optic 采用 TypeX,关注其 _connections 字段,遍历连接列表,并关注每个连接的第三个字段(价格)。结果是一个按顺序遍历TypeX 中所有价格的光学元件。

    要索引这个光学元件,我们需要将未索引的traverse“升级”为索引的traversed。然后,我们要使用保留索引的合成运算符.&gt;&lt;.,其中小于/大于符号指向具有我们想要的索引的光学部分。 (在具有多个索引的更复杂场景中,您可以使用&lt;.&gt; 将来自两个光学器件的索引组合成索引对(i,j)。)

    我们就是这样得到的:

    connections .> traversed <. _3
    

    它仍然按顺序遍历TypeX中的所有价格,但它还携带了遍历中的索引。

    请注意,setInitPrices 实际上是可以轻松编写为“一次性”镜头计算的函数之一。 map setIndexPrices 和递归只是遍历嵌套列表,所以它们相当于光学 traverse . traverse。所以,我们可以使用:

    setInitPrices' :: [[Typex]] -> [[Typex]]
    setInitPrices' = traverse .> traverse .> connections .> traversed <. _3 .@~ f
      where f i = 2 * fromIntegral i
    

    最后,值得注意的是,如果您有一个复杂的索引光学元件,例如:

    a .> b .> c .> d <. e <. f <. g
    

    出于晦涩的原因(运算符的右结合性以及.&gt;. 相同的事实),这始终等同于:

    a . b . c .> d <. e . f . g
    

    这是更常见的写法。所以,setInitPrices' 的最终版本是:

    setInitPrices' :: [[Typex]] -> [[Typex]]
    setInitPrices' = traverse . traverse . connections .> traversed <. _3 .@~ f
      where f i = 2 * fromIntegral i
    

    【讨论】:

    • 正是我需要的。也感谢您的详细解释。这个问题中的示例完美无缺,但在我自己的代码中使用它会产生以下错误:* Ambiguous type variable t0' 由于使用了traverse' prevents the constraint (Traversable t0)' 而被解决。相关绑定包括 setInitPrices' :: t0 (t1 MyType) -> t0 (t1 MyType) 可能的修复:使用类型注释来指定什么 t0' should be 函数类型已明确说明,那么这意味着什么注释?
    • 此消息声称setinitPrices' 没有类型签名。您是否可能在类型签名和定义中以不同的方式拼写函数名称?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多