Haskell 是不是不可能让复合透镜绑定?
我很难理解通过帮助类型检查器,下面的内容是可行的,还是完全不可能的。 设置有点随意,我只需要一些带有镜头的嵌套数据类型,这里称为Haskell 是不是不可能让复合透镜绑定?,haskell,functor,haskell-lens,unification,Haskell,Functor,Haskell Lens,Unification,我很难理解通过帮助类型检查器,下面的内容是可行的,还是完全不可能的。 设置有点随意,我只需要一些带有镜头的嵌套数据类型,这里称为A,B,C 我的问题是,如果我立即使用它调用类似于view的东西,我可以使用复合镜头(bLens.a),但是如果我尝试让bind并给它命名,我会收到错误消息 {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE
A
,B
,C
我的问题是,如果我立即使用它调用类似于view
的东西,我可以使用复合镜头(bLens.a)
,但是如果我尝试让bind并给它命名,我会收到错误消息
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Debug where
import Control.Eff
import Control.Eff.Reader.Strict
import Control.Lens
data A = A
data B = B
{ _a :: A
}
makeLenses ''B
data C = C
{ _b :: B
}
makeLenses ''C
askLensed :: ( Member (Reader r) e ) => Lens' r a -> Eff e a
askLensed l = view l <$> ask
works :: ( Member (Reader C) e ) => Lens' C B -> Eff e A
works bLens = do
askLensed (bLens . a)
doesNotWork :: ( Member (Reader C) e ) => Lens' C B -> Eff e A
doesNotWork bLens = do
let compositeLens = bLens . a
askLensed compositeLens
doesNotWork2 :: ( Member (Reader C) e ) => Lens' C B -> Eff e A
doesNotWork2 bLens = do
let compositeLens :: Lens' C A = bLens . a
askLensed compositeLens
butThisIsFine :: Lens' C B -> Lens' C A
butThisIsFine bLens =
let compositeLens = bLens . a in compositeLens
以及:
我尝试添加类型签名,明确量化了
f
和函子
约束,但迄今为止没有成功。简化许多事情的经验法则是不要使用镜头(或镜头
,或Setter
等)作为函数参数,除非您确实需要它,否则使用optic多态性,而是使用ALens
(或ALens'
或ASetter
)版本,这样可以避免秩2多态性问题
问题是,如果在do
块中给compositeLens
一个名称,那么它必须有一个不能再从上下文推断的类型。但是,Lens'ca
是一个隐藏的多态类型,这使得类型推断相当复杂。如果您给出一个明确的签名,实际上是可以的:
doesActuallyWork2 :: ( Member (Reader C) e ) => Lens' C B -> Eff e A
doesActuallyWork2 bLens = do
let compositeLens :: Lens' C A
compositeLens = bLens . a
askLensed compositeLens
您的版本doesNotWork2
不起作用,因为带有内嵌签名的定义被翻转到RHS,如
doesNotWork2 :: ( Member (Reader C) e ) => Lens' C B -> Eff e A
doesNotWork2 bLens = do
let compositeLens = bLens . a :: Lens' C A
askLensed compositeLens
…其中,compositeLens
再次尝试将刚刚给定的类型专门化为一个特定的函子,这是无法完成的
更直接的解决方案是完全避免这种局部多态性,而您实际上并不需要这种多态性:如果将ALens'
作为参数,则局部绑定会自动采用单态类型:like
worksEasily :: ( Member (Reader C) e ) => ALens' C B -> Eff e A
worksEasily bLens = do
let compositeLens = bLens . a
askLensed compositeLens
其实不完全是这样,;事实证明,您不想在这里使用ALens
,而是获取
。找到这个问题的最简单方法是删除askLensed的签名,让编译器告诉你它推断出了什么,然后从中向后操作
askLensed :: ( Member (Reader r) e ) => Getting a r a -> Eff e a
askLensed l = view l <$> ask
worksEasily :: ( Member (Reader r) e ) => Getting A r B -> Eff e A
worksEasily bLens = do
let compositeLens = bLens . a
askLensed compositeLens
askLensed::(成员(读者r)e)=>获取r a->Eff e a
askLensed l=视图l询问
轻松工作::(成员(读者r)e)=>获得r B->Eff e A
工作地点:bLens=do
让复合元素=混合元素。A.
斜纹菊科植物
感谢您的详细回答!我有一种预感,doesNotWork2
因为你提到的原因失败了,我不知道a…
家族。对于我的大多数用例,我可能不需要秩-2多态性,所以这是完美的!
worksEasily :: ( Member (Reader C) e ) => ALens' C B -> Eff e A
worksEasily bLens = do
let compositeLens = bLens . a
askLensed compositeLens
askLensed :: ( Member (Reader r) e ) => Getting a r a -> Eff e a
askLensed l = view l <$> ask
worksEasily :: ( Member (Reader r) e ) => Getting A r B -> Eff e A
worksEasily bLens = do
let compositeLens = bLens . a
askLensed compositeLens