我有以下型号
import monocle.macros.Lenses
import monocle.function.all._
import monocle.std.list._
@Lenses("_") case class Poll(pollChoices: List[PollChoice], totalVoteCount: Int)
@Lenses("_") case class PollChoice(id: Int, value: Int, percentage: Int)
Run Code Online (Sandbox Code Playgroud)
我想要实现的是通过更新pollChoices列表中每个元素的所有百分比属性来更新Poll的pollChoices属性.我的问题是,新的百分比值是基于价值的属性PollChoice和totalValueCount中的投票.
到目前为止我所做的是:
val poll = Poll(List(PollChoice(1,3,0), PollChoice(2,5,0)), 8)
(Poll._pollChoices composeTraversal each composeLens PollChoice._percentage)
.modify(oldPercentage => oldPercentage + 1)(poll)
Run Code Online (Sandbox Code Playgroud)
但是这样我只能访问我在修改步骤中更新的元素的百分比属性,我也需要该值.
我假设我需要使用Traversable来进行这种修改,但我不确定如何.谢谢.
我试图找出最简洁的方法来修改嵌套在Maybe
类型(或其他类型的建模偏好)内的值.
以下是示例设置:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Outer = Outer { _inner :: Maybe Inner }
deriving (Show)
data Inner = Inner { _foo :: Int }
deriving (Show)
makeLenses ''Outer
makeLenses ''Inner
Run Code Online (Sandbox Code Playgroud)
通过以下方式以一种混乱的方式执行此操作非常容易lens
:
wibble :: Outer -> Maybe Outer
wibble o = do i <- view inner o
let i' = over foo succ i
return $ set inner (Just i') o
Run Code Online (Sandbox Code Playgroud)
为了说明为什么这是令人讨厌的,这是我想要写的:
wibble' :: Outer -> Maybe Outer
wibble' = overish inner.foo …
Run Code Online (Sandbox Code Playgroud) 我很欣赏Control.Lens包.它确实有助于稍微弱的Haskell记录语法.我正在研究图书馆的某些部分,其中表现是一个问题.有没有人知道如果有的话,使用通过类型类暴露的简单镜头(如下所示)与功能中的基本模式匹配相比会有什么性能损失?使用像这样的镜头有可能成为记录命名空间冲突问题的一个很好的工作.我可以自己设置一些基准测试,但是如果有人可以帮我解决问题,我很好奇.谢谢.
class LensX v where
_x :: Functor f => (Double -> f Double) -> v -> f v
class LensY v where
_y :: Functor f => (Double -> f Double) -> v -> f v
class LensZ v where
_z :: Functor f => (Double -> f Double) -> v -> f v
Run Code Online (Sandbox Code Playgroud)
instance LensX Vec3 where
_x f (Vec3 x y z) = fmap (\x' -> Vec3 x' y z) (f x)
instance LensY Vec3 …
Run Code Online (Sandbox Code Playgroud) 我想A -> Bool
用A的一些镜头创建一个函数.例如:
data A = A { _foo :: Int, _bar :: Int }
makeLenses ''A
l :: [A]
l' = filter (\a -> a^.foo > 100) l
Run Code Online (Sandbox Code Playgroud)
过滤谓词看起来有点块状.((>100).(^.foo))
并没有好多少.没有镜头,我会用((>100) . foo)
.
有没有一种很好的方法来创建这样的谓词lens
?理想情况下,它也允许谓词(\a -> a^.foo > 100 && a^.bar < 50)
.
我经常发现自己使用这种模式:
do
let oldHeaders = mail ^. headers
put $ (headers .~ (insert header value oldHeaders)) mail
Run Code Online (Sandbox Code Playgroud)
这看起来像Control.Lens应该能做的事情,但我想我还没有找到合适的操作员.有没有更好的办法?另外,在这段代码中我还应该做些什么吗?
我正在努力使用该lens
库来解决特定问题.我想通过
到另一个功能,g
.我传递了镜头和数据结构,因为g
需要来自数据结构的一些共享信息以及一条信息.(如果它有帮助,数据结构包含关于联合概率分布的信息,但g
只能在边缘上工作,需要知道我正在看哪个边缘.两个边缘之间的唯一区别是它们与其定义的其余部分的平均值在数据结构中共享).
我的第一次尝试看起来像这样
f :: Functor f => Params -> ((Double -> f Double) -> Params -> f Params) -> a
f p l = g (l %~ upd $ p) l
where upd = ...
g p x = go p p^.x
Run Code Online (Sandbox Code Playgroud)
但是在编译过程中失败了,因为它f
被推断为Identity
更新和Const Double
getter.
完成我想做的最好的方法是什么?我可以想象能够做到以下之一:
谢谢你的帮助!
有没有办法让我只从具有镜头的模块中导出特定的吸气剂xor setter?
例如,让我们假设一个数据结构具有一直存在的不变性,>= 0
仅通过递增它并仅使用初始值创建来修改0
:
module Something
( Counter
-- export only `count` getter
, make
, increment
) where
data Counter = Counter { _count :: Int } deriving (Eq)
makeLenses ''Positive
make :: Counter
make = Counter 0
increment :: Counter -> Counter
increment c = c ^. count %~ (+1)
Run Code Online (Sandbox Code Playgroud)
我怎么能只导出count
吸气剂?
是否有相当于makeLenses
GADT?如果我有一个简单的GADT
:
data D a b where
D :: (Ord a, Ord b) => !a -> !b -> D a b
Run Code Online (Sandbox Code Playgroud)
有没有办法通过传入构造函数和字段名称列表自动生成镜头?
我的用例基于以下模型:
struct Person {
let name: String
let houses: [House]
}
struct House {
let owner: Person
}
Run Code Online (Sandbox Code Playgroud)
现在,理想情况下,我希望保持双向关系,要求每个房子只有一个所有者,其中所有者也应该知道其所有房屋.
使用上述数据结构,是否可以创建实例,House
并且Person
两者之间存在关系,并且对象基本上是相互指向的?
我猜这个的措辞已经有点误导了,因为由于struct
s 的值语义,它们并没有真正指向任何地方,而只是持有值的副本.看起来很明显,用双向关系创建这两个对象是不可能的,但我仍然想确定并在这里提出这个问题!
一个明显的解决方案也是使用houses
和owner
变量使用var
而不是let
在声明它们时,然后可以在每个的初始化器中维护关系struct
:
struct Person {
let name: String
var houses: [House]
init(name: String, houses: [House]) {
self.name = name
self.houses = houses
self.houses = houses.map { (house: House) in
var newHouse = house
newHouse.owner = self
return newHouse
}
}
}
struct House …
Run Code Online (Sandbox Code Playgroud) zoom
允许我们在实际定义了更多变量的上下文中使用仅使用某些状态变量的状态操作.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad.Trans.State
import Control.Monad.IO.Class
data Galaxy = Galaxy {
_solarSys :: SolarSystem
, _otherStars :: String
} deriving (Show)
data SolarSystem = SolarSystem {
_sun :: Float
, _planets :: Int
} deriving (Show)
makeLenses ''SolarSystem
makeLenses ''Galaxy
main = (`runStateT`Galaxy (SolarSystem 2e+30 8) "") $ do
zoom solarSys $ do
sun -= 1e+23
planets += 1
liftIO . print =<< get
Run Code Online (Sandbox Code Playgroud)
Galaxy {_solarSys = SolarSystem {_sun = 1.9999999e30, _planets = 9}, …
lenses ×10
haskell ×8
haskell-lens ×4
gadt ×1
immutability ×1
invariants ×1
ios ×1
monocle ×1
performance ×1
scala ×1
state-monad ×1
swift ×1