Aad*_*hah 12 haskell lenses traversable
我试图通过在Haskell中实现它来了解镜头.我已经实现了view如下组合器:
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
import Data.Traversable
type Lens s a = Functor f => (a -> f a) -> s -> f s
view :: Lens s a -> s -> a
view lens = getConst . lens Const
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试与它一起使用时,traverse我收到以下错误消息:
Prelude> :load Lens.hs
[1 of 1] Compiling Main ( Lens.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t view traverse
<interactive>:1:6:
Could not deduce (Applicative f) arising from a use of ‘traverse’
from the context (Traversable t)
bound by the inferred type of it :: Traversable t => t a -> a
at Top level
or from (Functor f)
bound by a type expected by the context:
Functor f => (a -> f a) -> t a -> f (t a)
at <interactive>:1:1-13
Possible fix:
add (Applicative f) to the context of
a type expected by the context:
Functor f => (a -> f a) -> t a -> f (t a)
or the inferred type of it :: Traversable t => t a -> a
In the first argument of ‘view’, namely ‘traverse’
In the expression: view traverse
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不明白这个错误信息.请解释它的含义以及如何解决它.
ben*_*ofs 10
至于其他的答案已经解释的问题是,view预期的东西,对于任何工作Functor f,但traverse只有工作,如果f是还Applicative(有仿函数不属于应用性).
在lens,通过使view不Rank2参数的类型解决问题(事实上,镜头中的大多数功能不使用镜头类型的同义词,它们总是使用较弱的东西).对于您的功能,请注意view只能使用f ~ Const.这就是您可以将类型签名更改为:
view :: ((a -> Const a a) -> s -> Const a s) -> s -> a
Run Code Online (Sandbox Code Playgroud)
实现可以保持不变,但现在view也适用于traverse:
view traverse :: (Traversable t, Monoid a) => t a -> a
Run Code Online (Sandbox Code Playgroud)
注意额外的Monoid约束.这种约束会出现,因为如果你设置f ~ Const a的traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a),你需要一个实例Applicative (Const a).但是那个例子有一个Monoid限制a.这也是有道理的,因为遍历可能是空的或包含多个元素,所以你需要mempty和mappend.