haskell 有没有一种方法来合成具体化的镜头?

ruarlubt  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(125)

我尝试使用透镜库来解决以下问题:
给定树的列表版本,创建一棵树。范例:

Given:
  [1,2,3,4,5,6,7]

I should make a tree:
     1
   2   3
  4 5 6 7

字符串
我的解决方案是使用状态单子和透镜根据深度创建节点。
我的树数据类型:

data Tree a = Nil | Node a (Tree a) (Tree a) deriving (Show)


一个我想要的字符串版本,用于计算镜头:

calculateSetters 1 = ["_Node . _2", "_Node . _3"]
calculateSetters n = (++) <$> calculateSetters (n-1) <*> [ "_Node . _2", "_Node . _3" ]

-- where "_Node" is a prism and "_2" and "_3" are lenses


非字符串版本将输出所有的镜头到给定深度的空孩子,我可以使用.~设置。非字符串版本的要点如下:

calculateSetters n = Setter <$> combinations where
  combinations = (.) <$> calculateSetters (n-1) <*> [ _Node . _2, _Node . _3 ]


我遇到了两个问题
1.我显然不能Map具体化器构造函数(fmap Setter [ _1, _1]是一个错误,但[Setter _1, Setter _1]不是)。我读到这可能是因为镜头是多态的,最终绑定到一些具体的东西,除非我立即具体化他们。
1.我不能做一个具体化的透镜[Setter _1],然后以某种方式将它与另一个具体化的镜头[Setter _2]组合得到[Setter $ _1 . _2]。看起来你可以在ghci中一次性使用::t Setter $ runSetter (Setter _2) . runSetter (Setter _2)似乎可以进行类型检查,但我不能使用列表。
最后我硬编码了几个这样的代码:

calculateSetters :: Int -> [ReifiedSetter (Tree Int) (Tree Int) (Tree Int) (Tree Int)]
calculateSetters 1 =
  [ Setter $ _Node . _2,
    Setter $ _Node . _3
  ]
calculateSetters 2 =
  [ Setter $ _Node . _2 . _Node . _2,
    Setter $ _Node . _2 . _Node . _3,
    Setter $ _Node . _3 . _Node . _2,
    Setter $ _Node . _3 . _Node . _3
  ]
calculateSetters 3 =
  [ Setter $ _Node . _2 . _Node . _2 . _Node . _2,
    Setter $ _Node . _2 . _Node . _2 . _Node . _3,
    Setter $ _Node . _2 . _Node . _3 . _Node . _2,
    Setter $ _Node . _2 . _Node . _3 . _Node . _3,
    Setter $ _Node . _3 . _Node . _2 . _Node . _2,
    Setter $ _Node . _3 . _Node . _2 . _Node . _3,
    Setter $ _Node . _3 . _Node . _3 . _Node . _2,
    Setter $ _Node . _3 . _Node . _3 . _Node . _3
  ]
calculateSetters 4 =
  [ Setter $ _Node . _2 . _Node . _2 . _Node . _2 . _Node . _2,
    Setter $ _Node . _2 . _Node . _2 . _Node . _2 . _Node . _3,
    Setter $ _Node . _2 . _Node . _2 . _Node . _3 . _Node . _2,
    Setter $ _Node . _2 . _Node . _2 . _Node . _3 . _Node . _3,
    Setter $ _Node . _2 . _Node . _3 . _Node . _2 . _Node . _2,
    Setter $ _Node . _2 . _Node . _3 . _Node . _2 . _Node . _3,
    Setter $ _Node . _2 . _Node . _3 . _Node . _3 . _Node . _2,
    Setter $ _Node . _2 . _Node . _3 . _Node . _3 . _Node . _3,
    Setter $ _Node . _3 . _Node . _2 . _Node . _2 . _Node . _2,
    Setter $ _Node . _3 . _Node . _2 . _Node . _2 . _Node . _3,
    Setter $ _Node . _3 . _Node . _2 . _Node . _3 . _Node . _2,
    Setter $ _Node . _3 . _Node . _2 . _Node . _3 . _Node . _3,
    Setter $ _Node . _3 . _Node . _3 . _Node . _2 . _Node . _2,
    Setter $ _Node . _3 . _Node . _3 . _Node . _2 . _Node . _3,
    Setter $ _Node . _3 . _Node . _3 . _Node . _3 . _Node . _2,
    Setter $ _Node . _3 . _Node . _3 . _Node . _3 . _Node . _3
  ]
calculateSetters _ = error "unsupported; too lazy"


这是可行的,但我想知道是否以及如何通过编程来做到这一点?

emeijp43

emeijp431#

你当然可以构造具体化的setter,尽管我不知道有什么标准函数可以这样做。但它可以用显而易见的方式来实现:

composeSetters :: ReifiedSetter' a b -> ReifiedSetter' b c -> ReifiedSetter' a c
composeSetters (Setter f) (Setter g) = Setter (f . g)

字符串
然后,其他的一切都可以只使用具体化的setters来完成,因此没有非 predicate 问题:

calculateSetters :: Int -> [ReifiedSetter' (Tree Int) (Tree Int)]
calculateSetters 1 =
  [ Setter (_Node . _2)
  , Setter (_Node . _3)
  ]
calculateSetters n
     = composeSetters <$> calculateSetters (n-1) <*> calculateSetters 1


可编译版本:

{-# LANGUAGE RankNTypes      #-}
{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Tree a = Nil
            | Node { _nodeValue :: a
                   , _lSubtree :: Tree a
                   , _rSubtree :: Tree a
                   }
  deriving (Show)

makeLenses ''Tree

composeSetters :: ReifiedSetter' a b -> ReifiedSetter' b c
                        -> ReifiedSetter' a c
composeSetters (Setter f) (Setter g) = Setter (f . g)

subtreeSetters :: [[ReifiedSetter' (Tree Int) (Tree Int)]]
subtreeSetters
   = [Setter id]
   : [ composeSetters <$> strs <*> [Setter lSubtree, Setter rSubtree]
     | strs <- subtreeSetters ]

相关问题