是否有相当于makeLenses
GADT?如果我有一个简单的GADT
:
data D a b where
D :: (Ord a, Ord b) => !a -> !b -> D a b
Run Code Online (Sandbox Code Playgroud)
有没有办法通过传入构造函数和字段名称列表自动生成镜头?
来玩个游戏.我们将使用两个桩,两个都由黑色/白色侧面芯片组成.
data Pile = Pile { _blacks, _whites :: Int }
makeLenses ''Pile
data Game = Game { _pileA, _pileB :: Pile }
makeLenses ''Game
Run Code Online (Sandbox Code Playgroud)
一个非常聪明的举动是将A堆中的黑色芯片和白色芯片 - 在B堆中翻转.但是如何?
cleverMove :: Game -> Game
cleverMove game = game & pileA . blacks -~ 1
& pileA . whites +~ 1
& pileB . blacks +~ 1
& pileB . whites -~ 1
Run Code Online (Sandbox Code Playgroud)
不是很优雅.如何在不参考每个桩两次的情况下进行此操作?
我想出的唯一的事情(我不喜欢它):
cleverMove game = game & pileA %~ (blacks -~ 1)
. (whites +~ 1)
& pileB …
Run Code Online (Sandbox Code Playgroud) 我正在尝试对包含元素列表的嵌套数据结构进行操作.在用各种方法解决之后,我终于决定使用镜头作为最好的方法.它们完美地用于查找和修改结构的特定元素,但到目前为止,我对如何添加新元素感到困惑.
从我读过的内容来看,我无法在技术上使用Traversal,因为它违反了Traversal定律,将新元素插入到列表中,并且假设我甚至可以首先使用Traversal找出如何做到这一点(我对Haskell仍然相当弱,并且镜头包装中大多数东西的类型签名让我头晕目眩.
具体来说,我想要完成的是,在匹配特定选择器的元素列表中找到一些元素,然后在匹配元素之前或之后插入一个新元素(函数的不同参数在之前或之后)比赛).Control.Lens是否已经拥有可以完成我正在尝试做的事情,而且我对类型签名的理解太弱而无法看到它?有没有更好的方法来完成我想要做的事情?
如果我只是想在列表的开头或结尾添加一个新元素,那么这将是相当微不足道的,但是将它插入特定于中间的某个地方是困难的部分.在我编写的一些前镜头代码中,我使用折叠来完成我想要的东西,但它开始变得粗糙在结构的更深嵌套部分(EG折叠内部的折叠内部)所以我转向Control.Lens试图解开一些混乱.
任何人都可以用OCaml解释*什么是镜头?
我试图谷歌它,但几乎所有这些都在Haskell的世界.
只想在OCaml的世界中为它做一些简单的演示,比如它是什么,它可以用于什么,等等.
在处理一个名为AppState
I want 的状态时,需要跟踪实例的数量.这些实例具有不同类型的ID InstanceId
.
因此,我的州看起来像这样
import Control.Lens
data AppState = AppState
{ -- ...
, _instanceCounter :: Map InstanceId Integer
}
makeLenses ''AppState
Run Code Online (Sandbox Code Playgroud)
当没有计算具有给定id的实例时,跟踪计数的函数应该产生1,n + 1
否则:
import Data.Map as Map
import Data.Map (Map)
countInstances :: InstanceId -> State AppState Integer
countInstances instanceId = do
instanceCounter %= incOrSetToOne
fromMaybe (error "This cannot logically happen.")
<$> use (instanceCounter . at instanceId)
where
incOrSetToOne :: Map InstanceId Integer -> Map InstanceId Integer
incOrSetToOne m = case Map.lookup instanceId …
Run Code Online (Sandbox Code Playgroud) 我正在尝试阅读Edward Kmett的Lens包中的文档 .我不熟悉很多使用的术语(profunctor,isomorphism,monomorphic,contravariant,bifunctor等...)
在这个库中使用这些词汇时,学习一些词汇的好资源是什么.
假设我的镜头at _
需要一些Maybe a
:
import Data.Map as M
m = M.fromList [(1,(2,3))]
--set 2nd element
m ^. at 1 .~ Just (4,5)
--gives fromList [(1,(4,5))]
m ^. at 1 .~ Nothing
--gives fromList ()
Run Code Online (Sandbox Code Playgroud)
现在假设我想用另一个镜头来构图.这个镜头返回的事实Maybe a
阻止我直接这样做.
m ^. at 1 . _2 .~ Just 4
--error
-- I want to get M.fromList [(1,(2,4))]
Run Code Online (Sandbox Code Playgroud)
这样做的正确方法是什么?
镜头是一个执行不可变记录修改的函数:它复制记录修改其内容的一部分.镜头是一个库,允许您组合镜头,以获得更复杂的修改.
我正在寻找定义反向抽象的正确术语.一些比较两个对象并返回它们之间差异的函数.这些功能也产生了一个系统.每个修改可以与细粒度描述"记录内的字段C内的字段B内的字段A"或者记录内的粗"字段C"同时表示.因此,您可以使用所需的准确度进行匹配修改.
我需要编写代码来比较记录并对其中的修改做出反应.我想避免重新发明轮子.我试图谷歌反向镜头,但淹没在不相关的输出.
类似的类型Maybe (Lens' a b)
不起作用,因为Lens'
在引擎盖下是Rank-2类型,不能在没有-XImpredicativeTypes
扩展名的类型构造函数中包装(在GHC中实际上不支持).
因此,提供一个在道德上具有类型的函数的最佳类型是什么
foo :: A -> Maybe (Lens' B C)
Run Code Online (Sandbox Code Playgroud)
一种可能性是推迟Maybe
到通过的延续
foo' :: ? y . A -> (Lens' B C -> y) -> Maybe y
Run Code Online (Sandbox Code Playgroud)
但我并不特别喜欢.
import Control.Lens
import Control.Lens.TH
data Foo = Foo {
_bar, _baz :: Int
}
makeLenses ''Foo
Run Code Online (Sandbox Code Playgroud)
现在,如果我想修改两个int字段,我可以做
barbaz :: Setter' Foo Int
barbaz = sets $ \foo f -> foo & bar %~ f
& baz %~ f
Run Code Online (Sandbox Code Playgroud)
但这似乎是一种非常难看的手动方式.
使用镜头/箭头组合器可以直接实现吗?
lenses ×10
haskell ×8
haskell-lens ×4
arrows ×1
gadt ×1
list ×1
ocaml ×1
state-monad ×1
vocabulary ×1