一个函数的类型签名是什么,它可以像 (& f %~) 和 (^.f) 一样应用,其中运算符来自 Lens 库?

What would be the type signature of a function that can be applied both like (& f %~) and (^. f) where operators are from Lens library?

我有一个函数可以从记录中获取值并将其设置到不同记录中的相同字段。

我想做的是了解它背后的机制是如何工作的

setToPercent perc basedOn toSetOn = setStat
    where baseStat = basedOn ^. _func -- type is Maybe Float
          percentDelta = (\a -> perc * a) <$> baseStat -- Maybe Float
          setStat = toSetOn & _func %~ (\a -> (+) <$> a <*> percentDelta)

其中 _func 定义为 MyDataType -> Maybe Float(记录语法中的默认函数。)

而且它的工作原理与我预期的一样。我想知道的是 _func 的类型签名。

我知道这里 basedOn ^. _func, _func 会有这样的类型 Getting (f0 Float) MyDataType (f0 Float)

这里 toSetOn & _func %~ (\a -> (+) <$> a <*> percentDelta_func 的类型是 ASetter Weapon Weapon (f0 Float) (f0 Float) 其中数据 WeaponMyDataType 基本上是具有相同构造函数的相同数据类型。

但我不确定整体类型是什么。 如果我将 setToPercent w.r.t _func 概括为

中的函数类型会是什么
setToPercent fnToApply perc basedOn toSetOn = setStat
    where baseStat = basedOn ^. fnToApply -- type is Maybe Float
          percentDelta = (\a -> perc * a) <$> baseStat -- Maybe Float
          setStat = toSetOn & fnToApply %~ (\a -> (+) <$> a <*> percentDelta)

有趣的问题!

I know here basedOn ^. _func, _func would have the type Getting (f0 Float) MyDataType (f0 Float)

and here toSetOn & _func %~ (\a -> (+) <$> a <*> percentDelta, _func would have the type ASetter Weapon Weapon (f0 Float) (f0 Float)

因此,非正式地,_func 既是 getter 又是 setter。查看 Oleg Grenrus 在 the lens homepage on Hackage or the one on the Glassery blogpost 上的图表,getters 和 setters 的“最不共同的祖先”是透镜。

镜头库提出了至少两种镜头表示形式,一种是多态的 Lens' Weapon (f0 Float)(定义中包含 forall),另一种是单态的 ALens' Weapon (f0 Float)(取代了 forall 与一个具体的函子)。

由于我们希望此处 _func 自动专门化为 ASetterGetting,一种直接的方法是使用多态方法(这需要 RankNTypes 如果 _func 是一个参数而不是顶层绑定)。

_func :: Lens' Weapon (f0 Float)   -- Polymorphic
      -- specializes to
      :: Getting (f0 Float) Weapon (f0 Float)
      :: ASetter' Weapon (f0 Float)

还有另一种使用单态版本的方法。当 _func 是函数参数时,我发现这更符合习惯,因为它使调用者更容易传递合适的参数。但是,当我们实际使用它时,我们必须明确地概括 _func

_func :: ALens' Weapon (f0 Float)   -- Monomorphic

cloneLens _func :: Lens' Weapon (f0 Float)  -- Polymorphic again

-- The ALens' type synonym usually appears in argument position
myFun :: ALens' Foo Bar -> MyResult
myFun _func = ...

-- Example usage
basedOn ^. cloneLens _func
toSetOn & cloneLens _func %~ ...