至少有三个流行的库用于访问和操作记录字段.我所知道的是:数据访问器,fclabels和镜头.
我个人开始使用数据访问器,现在我正在使用它们.然而最近在haskell-cafe上有一个fclabels优越的意见.
因此,我对这三个(也许更多)库的比较感兴趣.
有人可以向我解释功能性镜片吗?谷歌这是一个令人惊讶的困难主题,我没有取得任何进展.我所知道的是,它们提供了类似于OO的获取/设置功能.
我似乎无法找到在实际例子中使用什么镜头的任何解释.Hackage页面中的这一短段是我发现的最接近的段落:
该模块提供了访问和更新结构元素的便捷方式.它与Data.Accessors非常相似,但更通用,依赖性更低.我特别喜欢它如何干净地处理状态monad中的嵌套结构.
那么,它们用于什么?他们对其他方法有什么好处和坏处?他们为什么需要?
镜头似乎没有任何缺点,同时具有优于标准Haskell的显着优势:是否有任何理由我不应该尽可能使用镜头?有性能考虑吗?另外,模板Haskell是否有任何重大开销?
我正在观看Control.Lens
介绍视频.
这让我想知道为什么Setter
类型需要在仿函数中包装它.
它(大致)定义如下:
type Control.Lens.Setter s t a b = (Functor f) => (a -> f a) -> s -> f t
Run Code Online (Sandbox Code Playgroud)
假设我有一个名为Point
this的定义数据:
data Point = Point { _x :: Int, _y :: Int } deriving Show
Run Code Online (Sandbox Code Playgroud)
然后我可以xlens
像这样写自己的:
type MySetter s t a b = (a -> b) -> s -> t
xlens :: MySetter Point Point Int Int
xlens f p = p { _x = f (_x p) …
Run Code Online (Sandbox Code Playgroud) 有这些进口:
> import Control.Lens
Control.Lens> import qualified Data.Map as Map
Run Code Online (Sandbox Code Playgroud)
和一个定义如下的地图值:
Control.Lens Map> let m = Map.fromList [('a', 1), ('c', 3), ('b', 2)]
Run Code Online (Sandbox Code Playgroud)
我可以像这样一个接一个地得到它的元素:
Control.Lens Map> view (at 'b') m
Just 2
Run Code Online (Sandbox Code Playgroud)
我想知道的是,有一组这样的键:
Control.Lens Map> import qualified Data.Set as Set
Control.Lens Map Set> let keys = Set.fromList ['d', 'c', 'b']
Run Code Online (Sandbox Code Playgroud)
如何构建这样一个getter(我猜),使用它我将能够获得匹配元素的集合(或列表):
Control.Lens Map Set> view (**???**) m
[3, 2]
Run Code Online (Sandbox Code Playgroud)
请注意,结果只包含2个元素,因为键不匹配'd'
.
我试图通过给它一个镜头参数来重构我的函数(从xml-lens
包中).我错过了关于类型量词的一些东西.这里发生了什么?
*Main> let z name = listToMaybe $ pom ^.. root ./ ell name . text
*Main> :t z
z :: Text -> Maybe Text
*Main> let z name l = listToMaybe $ pom ^.. l ./ ell name . text
<interactive>:13:38:
Couldn't match expected type ‘(Element -> f Element)
-> Document -> f Document’
with actual type ‘t’
because type variable ‘f’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected …
Run Code Online (Sandbox Code Playgroud) 如果您浏览hackage上的Lens条目,Lens Github的回购,甚至谷歌关于Lens,您会发现许多部分参考资料,如介绍性教程/视频,示例,概述等.由于我已经了解了大部分基础知识,因此我正在寻找更完整的参考资料,以帮助我更多地了解高级功能.换句话说,我仍然不知道这意味着什么,并且找不到足够完整的资源来解释这个图形.想法?
假设我有一对转换函数
string2int :: String -> Maybe Int
int2string :: Int -> String
Run Code Online (Sandbox Code Playgroud)
我可以使用Optics轻松地代表这些.
stringIntPrism :: Prism String Int
但是,如果我想表示失败原因,我需要将它们作为两个单独的函数保留.
string2int :: String -> Validation [ParseError] Int
int2string :: Int -> String`
Run Code Online (Sandbox Code Playgroud)
对于这个简单的例子Maybe
非常好,因为我们总是可以假设失败是解析失败,因此我们实际上不必使用Either或Validation类型对此进行编码.
但是想象一下,除了解析Prism之外,我还想进行一些验证
isOver18 :: Int -> Validation [AgeError] Int
isUnder55 :: Int -> Validation [AgeError] Int
Run Code Online (Sandbox Code Playgroud)
将这些东西组合在一起是理想的,这样我就可以拥有
ageField = isUnder55 . isOver18 . string2Int :: ValidationPrism [e] String Int
这对于手工构建来说是相当微不足道的,但是它似乎是一个普遍的概念,在镜头/光学领域潜藏着可能存在的东西.是否存在处理此问题的现有抽象?
TL;博士
是否有一种标准的方法来实现部分镜头/棱镜/ iso,可以通过任意仿函数进行参数化,而不是直接绑定到Maybe?.
我上面使用了Haskell表示法,因为它更直接,但我实际上是在Scala中使用Monocle来实现它.但是,对于ekmett的Lens库特定的答案,我会非常满意.
我正在学习镜头包.我必须说这是一项相当具有挑战性的任务.
有人能告诉我如何使用拉链从镜头遍历一棵树吗?特别是,如何编写一个带有根列表并允许我访问子树分支的函数?
假设我有这棵树.如果我的输入是[1, 3]
,该功能应该允许我访问节点10和11.
import Control.Lens
import Data.Tree
import Data.Tree.Lens
testTree = Node 1 [ Node 2 [ Node 4 [ Node 6 [], Node 8 [] ],
Node 5 [ Node 7 [], Node 9 [] ] ],
Node 3 [ Node 10 [],
Node 11 [] ]
]
zipperTree = zipper testTree
Run Code Online (Sandbox Code Playgroud)
另外,我如何使用saveTape
和restoreTape
保存遍历路径(到StateT或IORef)?