标签: lenses

如何在没有Monoid实例的Control.Lens.Indexed中处理at的结果

我最近在Hackage上发现了镜头包,并且现在正试图在一个小的测试项目中使用它,如果我继续工作,它可能会在一个非常遥远的日子变成MUD/MUSH服务器.

这是我的代码的最小化版本,说明我现在遇到的问题,用于访问键/值容器的at镜头(在我的情况下是Data.Map.Strict)

{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, TemplateHaskell #-}
module World where
import Control.Applicative ((<$>),(<*>), pure)
import Control.Lens
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as DM
import Data.Maybe
import Data.UUID
import Data.Text (Text)
import qualified Data.Text as T
import System.Random (Random, randomIO)

newtype RoomId = RoomId UUID deriving (Eq, Ord, Show, Read, Random)
newtype PlayerId = PlayerId UUID deriving (Eq, Ord, Show, Read, Random)

data Room =
  Room { _roomId :: RoomId 
       , _roomName :: Text
       , _roomDescription :: Text
       , …
Run Code Online (Sandbox Code Playgroud)

haskell lenses haskell-lens

15
推荐指数
1
解决办法
1853
查看次数

结合镜头

使用镜头库我可以将修改功能应用于各个目标,如下所示:

Prelude Control.Lens> (1, 'a', 2) & _1 %~ (*3)
(3,'a',2)
Prelude Control.Lens> (1, 'a', 2) & _3 %~ (*3)
(1,'a',6)
Run Code Online (Sandbox Code Playgroud)

如何组合这些单独的镜头(_1_3),以便能够同时对两个目标执行此更新?我期待以下精神:

Prelude Control.Lens> (1, 'a', 2) & ??? %~ (*3)
(3,'a',6)
Run Code Online (Sandbox Code Playgroud)

haskell lenses haskell-lens

15
推荐指数
2
解决办法
1689
查看次数

Is there a van Laarhoven representation of `Optional`

Many types of optics have a van Laarhoven representation.

For example, a Lens of type Lens s t a b can be represented as:

 Functor f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)

Similarly a Traversal, can be represented in a similar way, swapping the Functor constraint for Applicative:

 Applicative f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)

几种光学框架(例如MonocleArrow)定义了一种类型Optional

在《单片眼镜光学》中,层次结构 Optional介于Lens和之间Traversal

根据我的理解:如果 …

haskell functional-programming scala lenses monocle-scala

15
推荐指数
1
解决办法
557
查看次数

避免使用镜头重复,同时深入复制到Map值

我有一个不可变的数据结构,我在地图中有嵌套值,如下所示:

case class TradingDay(syms: Map[String, SymDay] = Map.empty)
case class SymDay(sym: String, traders: Map[String, TraderSymDay] = Map.empty)
case class TraderSymDay(trader: String, sym: String, trades: List[Trade] = Nil)
Run Code Online (Sandbox Code Playgroud)

另外,我有一天中所有交易的清单,我想生成TradingDay结构,在哪里

case class Trade(sym: String, trader: String, qty: Int)
Run Code Online (Sandbox Code Playgroud)

我想通过折叠我的交易来弄清楚如何用镜头更新这个结构(见附录):

(TradingDay() /: trades) { (trd, d) =>
  def sym = trd.sym
  def trader = trd.trader
  import TradingDay._
  import SymDay._
  import TraderSymDay._
  val mod =
    for {
      _ <- (Syms member sym).mods(
             _ orElse some(SymDay(sym)))
      _ <- (Syms at sym andThen Traders …
Run Code Online (Sandbox Code Playgroud)

scala scalaz lenses

14
推荐指数
2
解决办法
963
查看次数

模拟Haskell中的交互状态对象

我正在编写一个Haskell程序,它涉及模拟一个抽象机器,它具有内部状态,接受输入并提供输出.我知道如何使用状态monad实现这一点,从而产生更清晰,更易于管理的代码.

我的问题是,当我有两个(或更多)有状态对象相互交互时,我不知道如何使用相同的技巧.下面我给出了一个高度简化的问题版本,并勾勒出我到目前为止的内容.

为了这个问题,让我们假设一个机器的内部状态只包含一个整数寄存器,因此它的数据类型是

data Machine = Register Int
        deriving (Show)
Run Code Online (Sandbox Code Playgroud)

(实际的机器可能有多个寄存器,程序指针,调用堆栈等等,但现在不要担心.)在上一个问题之后我知道如何使用状态monad实现机器,所以我不必显式传递其内部状态.在这个简化的示例中,导入后实现如下所示Control.Monad.State.Lazy:

addToState :: Int -> State Machine ()
addToState i = do
        (Register x) <- get
        put $ Register (x + i)

getValue :: State Machine Int
getValue = do
        (Register i) <- get
        return i
Run Code Online (Sandbox Code Playgroud)

这让我可以写出类似的东西

program :: State Machine Int
program = do
        addToState 6
        addToState (-4)
        getValue

runProgram = evalState program (Register 0)
Run Code Online (Sandbox Code Playgroud)

这会将6添加到寄存器,然后减去4,然后返回结果.状态monad跟踪机器的内部状态,以便"程序"代码不必明确跟踪它.

在命令式语言的面向对象样式中,这个"程序"代码可能看起来像

def runProgram(machine):
    machine.addToState(6)
    machine.addToState(-4)
    return machine.getValue()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果我想模拟两台彼此交互的机器,我可能会写

def …
Run Code Online (Sandbox Code Playgroud)

monads haskell state-monad lenses haskell-lens

14
推荐指数
2
解决办法
437
查看次数

具有代数类型的镜头包

我用镜头包编码.一切都很顺利,直到我试图访问代数类型的某个字段:

import Control.Lens

data Type = A { _a :: Char } | B

makeLenses ''Type

test1 = _a (A 'a')
test2 = (A 'a') ^. a

No instance for (Data.Monoid.Monoid Char)
  arising from a use of `a'
Possible fix:
  add an instance declaration for (Data.Monoid.Monoid Char)
In the second argument of `(^.)', namely `a'
In the expression: (A 'a') ^. a
In an equation for `test2': test2 = (A 'a') ^. a
Run Code Online (Sandbox Code Playgroud)

我可以选择_a,但我的真实程序中的数据类型更深,我打算使用镜头来降低我必须做的工作量.我一直在查看镜头库,但那里有很多,我不确定他是否处理过这种情况,或者它只是镜头库不支持的东西.

作为旁注,如果我实际上使用类似String的monoid作为数据类型而不是Char,那么它会编译并给出正确的答案,我不知道为什么.

编辑:在阅读了hammar的评论后,我尝试了这个,这有效:

test2 = (A 'a') …
Run Code Online (Sandbox Code Playgroud)

haskell lenses

13
推荐指数
1
解决办法
313
查看次数

如何使用Control.Lens更新列表的第i个元素?

我有一些数据类型

data Outer = Outer { _list :: [ Inner ] }
data Inner = Inner { _bool :: Bool }
Run Code Online (Sandbox Code Playgroud)

使用Control.Lens,我可以访问第i个内部的_bool(在'State Outer'monad中)

boolValue <- gets (^. list . to (!! i) . inner)
Run Code Online (Sandbox Code Playgroud)

我也想用类似的东西来更新这个值

list ^. (to (!! i)) ^. inner %= True
Run Code Online (Sandbox Code Playgroud)

然而(根据我的理解),'to'功能只会创建一个getter,而不是一个可用作getter或setter的真实镜头.

那么,我怎样才能将(!! i)转换为可以让我更新此字段的镜头?

haskell lenses

13
推荐指数
2
解决办法
2609
查看次数

在Scala中合并两个案例类,但是具有深层嵌套类型,没有镜头样板

类似于这个案例类问题,但有一个扭曲:

我有一个case类,它有一些深层嵌套的case类作为属性.举个简单的例子,

case class Foo(fooPropA:Option[String], fooPropB:Option[Int])
case class Bar(barPropA:String, barPropB:Int)
case class FooBar(name:Option[String], foo:Foo, optionFoo: Option[Foo], bar:Option[Bar])
Run Code Online (Sandbox Code Playgroud)

我想将两个FooBar案例类合并在一起,获取输入存在的值并将它们应用于现有实例,从而生成更新版本:

val fb1 = FooBar(Some("one"), Foo(Some("propA"), None), Some(Foo(Some("propA"), Some(3))), Some(Bar("propA", 4)))
val fb2 = FooBar(None, Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), None)), None)
val merged = fb1.merge(fb2)
//merged = FooBar(Some("one"), Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), Some(3))), Some(Bar("propA", 4)))
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用镜头来构建深层嵌套的属性更新; 但是,我觉得这需要大量的锅炉板代码:我需要一个镜头用于每个属性,而另一个组合镜头在父类中.这似乎是一个很多维护,即使使用的更简洁的镜头创作方法不成形.

棘手的部分是optionFoo元素:在这种情况下,两个元素都存在Some(value).但是,我想合并内部选项属性,而不仅仅是用fb2的新值覆盖fb1.

我想知道是否有一种很好的方法可以将这两个值合并在一起,只需要最少的代码.我的直觉告诉我尝试使用unapplycase类上的方法返回一个元组,迭代并将元组组合成一个新的元组,然后将元组应用回case类.

有没有更有效的方法来做这件事?

scala lenses

13
推荐指数
2
解决办法
2483
查看次数

将镜头使用与数据库访问协调

我最近一直在玩镜头,发现它们非常适合它们的预期用途 - 挖掘复杂的数据结构.但我最欣赏他们的一个领域是数据库访问(特别是sqlite,但我认为我的问题推广到大多数数据库),但我看不出任何方法来编写不会牺牲很多钱的镜头性能或粒度.

如果我从DB到表,从表到行,从行到列编写镜头(或者我认为可能是Prism,根据NULLable字段?),那么每个步骤都会导致数据库访问,意味着应该是一次访问至少4.

在另一方面,如果我的目标是地图DB访问1:1与透镜/棱镜的用途,我得到大做,一切镜头不能被分解成更小的碎片时,我希望只看到是什么列在表格中,等等.

使用具有DB的镜头是否有意义,如果是这样,我错过了一种明显的方法来避免重复工作以避免不必要的DB访问?

haskell lenses haskell-lens

13
推荐指数
1
解决办法
521
查看次数

镜头和部分镜头有什么区别?

"透镜"和"部分透镜"在名称和概念上看起来相似.他们有什么不同?在什么情况下我需要使用其中一个?

标记Scala和Haskell,但我欢迎与任何具有镜头库的功能语言相关的解释.

haskell scala scalaz lenses calmm

12
推荐指数
3
解决办法
1147
查看次数