我尝试使用透镜库来解决以下问题:
给定树的列表版本,创建一棵树。范例:
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"
型
这是可行的,但我想知道是否以及如何通过编程来做到这一点?
1条答案
按热度按时间emeijp431#
你当然可以构造具体化的setter,尽管我不知道有什么标准函数可以这样做。但它可以用显而易见的方式来实现:
字符串
然后,其他的一切都可以只使用具体化的setters来完成,因此没有非 predicate 问题:
型
可编译版本:
型