Generalized Newtype Deriving

社会主义新天地 提交于 2020-01-03 10:06:25

问题


Haskell can derive the instance for MonadState s in T1 below but not in T2 which is however a very similar type. In which way should I modify the code for T2 so that the instance for MonadState s can be automatically derived?

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Control.Monad.Reader
import Control.Monad.State

newtype T1 r s a = 
  T1 { runT1 :: ReaderT r (State s) a }
  deriving (Monad, MonadReader r, MonadState s)

newtype T2 r s a = 
  T2 { runT2 :: StateT r (State s) a }
  deriving (Monad, MonadState r, MonadState s)

回答1:


You can't have a type have two instances for MonadState. This is because MonadState is defined as

class Monad m => MonadState s m | m -> s where
    get :: m s
    set :: s -> m ()
    state :: (s -> (a, s)) -> m a

The key part is the | m -> s. This requires the extension FunctionalDependencies, and states that for any m, we automatically know the associated s. This means that for any given m, there can only be one choice for s that is valid. So you can't have it work for both MonadState r m and MonadState s m unless r ~ s. If r ~ s, then how would the compiler know which underlying monad for it to apply to? In this case, I think you'll also find that it'll be much easier to understand and work with the code if you create get and put functions that have suffixes to indicate which, like getInner, setInner and getOuter, setOuter.



来源:https://stackoverflow.com/questions/25693483/generalized-newtype-deriving

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!