3

让我从我想要解决的任务开始,可能我走错路了。我在玩具项目中使用了 Snap 框架,主要是它在Snapmonad 下的功能。我需要在它上面添加我的状态。我使用单子变压器:

type SnapApp a = StateT AppState Snap a

这在模块中定义,例如Base. 由于我在其他模块中需要它,因此我必须将其导出:

module Base
  ( ..
  , SnapApp
  ) where

这很好,但我希望该模块不导出SnapApp状态单子,因为我有一些复杂的处理来设置状态的一些属性。例如,会话。我必须在更改文件时写入文件,因此仅修改会话是错误的getput应该调用特殊函数。所以,我隐藏了使用newtype而不是数据导出contrustor:

newtype SnapApp a = SnapApp (StateT AppState Snap a)

我用修改会话等的功能使它成为我的类的实例。但是出现了问题:我丢失了Monad类和其他新的实例SnapApp。我坚持实施>>=

instance Monad SnapApp where
    return = SnapApp . return
    mx >>= fm = -- HOW?

谢谢!

4

2 回答 2

16

让类型指导您。你需要

(>>=) :: SnapApp a -> (a -> SnapApp b) -> SnapApp b

你有

(>>=) :: StateT AppState Snap a -> (a -> StateT AppState Snap b) -> StateT AppState Snap b

您需要转换:

  • 论据SnapApp a_StateT AppState Snap a
  • 论据a -> SnapApp b_a -> StateT AppState Snap b
  • 结果StateT AppState Snap bSnapApp b

1)使用模式匹配;定义:

fromSnapApp (SnapApp x) = x

2) 编写函数a -> SnapApp bSnapApp b -> StateT AppState b

3) 使用SnapApp

最后结果:

x >>= f = SnapApp (fromSnapApp x >>= (fromSnapApp . f)) 

或者:

SnapApp x >>= f = SnapApp (x >>= (fromSnapApp . f)) 

你不必写这个;如果启用GeneralizedNewtypeDeriving扩展,GHC 可以派生实例:

newtype SnapApp a = SnapApp (StateT AppState Snap a) deriving (Monad)
于 2012-05-26T10:01:08.600 回答
3

这种状态管理正是我们为您设计的 snaplets 来处理的。我们的 Handler monad 实际上只是一个新类型的包装器StateT s Snap,为了方便而内置了一些额外的东西。我们确实公开了一个 MonadState 实例,这是您试图避免的,但是您可以通过将您的状态类型封装在一个模块中而不为它导出任何访问器来处理这个问题。您可以只导出执行所有复杂属性处理的所需 Handler 函数。

于 2012-05-27T03:30:26.787 回答