Coroutine (Await Int) (State MyState) Int 的缩放实例
Zoom instance for Coroutine (Await Int) (State MyState) Int
我有一个深度嵌套的状态 MyState
,它在 Coroutine
中使用(来自 monad-coroutine 包):
Coroutine (Await Int) (State MyState) Int
而且我喜欢使用缩放(来自 lens)进行一些操作的可能性,因为它允许我写类似
的东西
zoom (company.assets) $ do
a.b = 3
c.d = 'good'
...
不幸的是,我无法为我拥有的 Coroutine
提出正确的 instance Zoom
声明。
我的尝试是这样的:
instance Zoom (Coroutine z s) (Coroutine z t) s t where
zoom l (Coroutine m) = undefined
但此时 GHC 已经告诉我
Expecting one more argument to ‘s’
The third argument of ‘Zoom’ should have kind ‘*’,
but ‘s’ has kind ‘* -> *’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) s t’
但是如果我做类似
instance Zoom (Coroutine z s) (Coroutine z t) (s a) (t a) where
zoom l (Coroutine m) = undefined
然后 GHC 抱怨:
Illegal instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) (s a) (t a)’
The liberal coverage condition fails in class ‘Zoom’
for functional dependency: ‘m -> s’
Reason: lhs type ‘Coroutine z s’ does not determine rhs type ‘s a’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) (s a) (t a)’
现在我明白了,我是在盲目地做某事,而不了解对我的实际期望。任何人都可以解释 Zoom
实例是如何为我的 Coroutine
定义的,以及为什么定义它(因此不仅对正确的声明感兴趣,而且对构造此类声明时的思考过程也有一些注意事项)?
错误
Expecting one more argument to ‘s’
The third argument of ‘Zoom’ should have kind ‘*’,
but ‘s’ has kind ‘* -> *’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) s t’
GHC 在这里抱怨类型不匹配
‘Zoom (Coroutine z s) (Coroutine z t) s t’
^ ^
Coroutine
的第二个类型参数应该是monad(* -> *
),而s
是state的类型(*
)作为第三个类型Zoom
的参数。实例声明应该是
instance (Functor f, Zoom m n s t) => Zoom (Coroutine f m) (Coroutine f n) s t
连同一些样板文件以满足 Zoom
的上下文:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
instance (Functor f, MonadState s m) => MonadState s (Coroutine f m) where
get = lift get
put = lift . put
type instance Zoomed (Coroutine s m) = Zoomed m
经过几个小时的检查,我意识到我上面建议的是不可能实现的,zoom
的类型太受限制,无法与 mapMonad
一起使用,我不知道办法克服它。然而,如果一切都是单态的,它仍然有效:
data MyState = MyState
{ _myRecord :: String }
$(makeLenses ''MyState)
zoomMyState :: Functor f => Coroutine f (State String) r -> Coroutine f (State MyState) r
zoomMyState = mapMonad (zoom myRecord)
我有一个深度嵌套的状态 MyState
,它在 Coroutine
中使用(来自 monad-coroutine 包):
Coroutine (Await Int) (State MyState) Int
而且我喜欢使用缩放(来自 lens)进行一些操作的可能性,因为它允许我写类似
的东西zoom (company.assets) $ do
a.b = 3
c.d = 'good'
...
不幸的是,我无法为我拥有的 Coroutine
提出正确的 instance Zoom
声明。
我的尝试是这样的:
instance Zoom (Coroutine z s) (Coroutine z t) s t where
zoom l (Coroutine m) = undefined
但此时 GHC 已经告诉我
Expecting one more argument to ‘s’
The third argument of ‘Zoom’ should have kind ‘*’,
but ‘s’ has kind ‘* -> *’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) s t’
但是如果我做类似
instance Zoom (Coroutine z s) (Coroutine z t) (s a) (t a) where
zoom l (Coroutine m) = undefined
然后 GHC 抱怨:
Illegal instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) (s a) (t a)’
The liberal coverage condition fails in class ‘Zoom’
for functional dependency: ‘m -> s’
Reason: lhs type ‘Coroutine z s’ does not determine rhs type ‘s a’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) (s a) (t a)’
现在我明白了,我是在盲目地做某事,而不了解对我的实际期望。任何人都可以解释 Zoom
实例是如何为我的 Coroutine
定义的,以及为什么定义它(因此不仅对正确的声明感兴趣,而且对构造此类声明时的思考过程也有一些注意事项)?
错误
Expecting one more argument to ‘s’
The third argument of ‘Zoom’ should have kind ‘*’,
but ‘s’ has kind ‘* -> *’
In the instance declaration for
‘Zoom (Coroutine z s) (Coroutine z t) s t’
GHC 在这里抱怨类型不匹配
‘Zoom (Coroutine z s) (Coroutine z t) s t’
^ ^
Coroutine
的第二个类型参数应该是monad(* -> *
),而s
是state的类型(*
)作为第三个类型Zoom
的参数。实例声明应该是
instance (Functor f, Zoom m n s t) => Zoom (Coroutine f m) (Coroutine f n) s t
连同一些样板文件以满足 Zoom
的上下文:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
instance (Functor f, MonadState s m) => MonadState s (Coroutine f m) where
get = lift get
put = lift . put
type instance Zoomed (Coroutine s m) = Zoomed m
经过几个小时的检查,我意识到我上面建议的是不可能实现的,zoom
的类型太受限制,无法与 mapMonad
一起使用,我不知道办法克服它。然而,如果一切都是单态的,它仍然有效:
data MyState = MyState
{ _myRecord :: String }
$(makeLenses ''MyState)
zoomMyState :: Functor f => Coroutine f (State String) r -> Coroutine f (State MyState) r
zoomMyState = mapMonad (zoom myRecord)