use*_*596 6 haskell haskell-lens
我试图使用镜头库来解决以下问题:
给定树的列表版本,创建一棵树。例子:
Given:
[1,2,3,4,5,6,7]
I should make a tree:
1
2 3
4 5 6 7
Run Code Online (Sandbox Code Playgroud)
我的解决方案是使用状态单子和透镜根据深度创建节点。
我的树数据类型:
data Tree a = Nil | Node a (Tree a) (Tree a) deriving (Show)
Run Code Online (Sandbox Code Playgroud)
我想要的一个字符串版本,用于计算镜片:
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
Run Code Online (Sandbox Code Playgroud)
非拉丝版本会将所有镜头输出到给定深度的空孩子,我可以使用 进行设置.~。非字符串版本的要点如下:
calculateSetters n = Setter <$> combinations where
combinations = (.) <$> calculateSetters (n-1) <*> [ _Node . _2, _Node . _3 ]
Run Code Online (Sandbox Code Playgroud)
我遇到的两个问题
fmap Setter [ _1, _1]是一个错误,但[Setter _1, Setter _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"
Run Code Online (Sandbox Code Playgroud)
哪个有效,但我想知道是否以及如何以编程方式执行此操作?
您当然可以编写具体化的设置器,尽管我不知道执行此操作的标准函数。但这可以通过明显的方式完成:
composeSetters :: ReifiedSetter' a b -> ReifiedSetter' b c -> ReifiedSetter' a c
composeSetters (Setter f) (Setter g) = Setter (f . g)
Run Code Online (Sandbox Code Playgroud)
然后,其他一切都可以仅使用具体化的 setter 来完成,因此不会出现必然的问题:
calculateSetters :: Int -> [ReifiedSetter' (Tree Int) (Tree Int)]
calculateSetters 1 =
[ Setter (_Node . _2)
, Setter (_Node . _3)
]
calculateSetters n
= composeSetters <$> calculateSetters (n-1) <*> calculateSetters 1
Run Code Online (Sandbox Code Playgroud)
可编译版本:
{-# 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 ]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
82 次 |
| 最近记录: |