首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >涵盖提升数据类型的所有情况。

涵盖提升数据类型的所有情况。
EN

Stack Overflow用户
提问于 2013-01-11 00:25:42
回答 1查看 143关注 0票数 5

因此,我最近提出了一个很好的想法,希望在严格的和懒惰的State转换器模块之间共享代码:

代码语言:javascript
复制
{-# LANGUAGE FlexibleInstances, DataKinds, KindSignatures #-}
module State where

data Strictness = Strict | Lazy
newtype State (t :: Strictness) s a = State (s -> (s, a))

returnState :: a -> State t s a
returnState x = State $ \s -> (s, x)

instance Monad (State Lazy s) where
  return = returnState
  State ma >>= amb = State $ \s -> case ma s of
    ~(s', x) -> runState (amb x) s'

instance Monad (State Strict s) where
  return = returnState
  State ma >>= amb = State $ \s -> case ma s of
    (s', x) -> runState (amb x) s'

get :: State t s s
get = State $ \s -> (s, s)

put :: s -> State t s ()
put s = State $ \_ -> (s, ())

您可以看到,getput在严格类型和惰性类型上都不存在任何复制--没有类型类实例,也没有任何东西。然而,尽管我介绍了Strictness的这两种可能的情况,但总的来说,我没有State t s a的Monad实例:

代码语言:javascript
复制
-- from http://blog.melding-monads.com/2009/12/30/fun-with-the-lazy-state-monad/
pro :: State t [Bool] ()
pro = do
  pro
  s <- get
  put (True : s)

-- No instance for (Monad (State t [Bool])) arising from a do statement

尽管需要FlexibleContexts,但以下内容工作正常

代码语言:javascript
复制
pro :: (Monad (State t [Bool])) => State t [Bool] ()
-- otherwise as before

然后,我可以在LazyStrict实例化LazyStrict,运行结果并得到我期望的结果。但为什么我要给出这样的背景呢?这是一个概念上的限制,还是一个实际的限制?是否有什么原因让我忽略了为什么Monad (State t s a)不存在,或者说还没有办法说服GHC呢?

(旁白:使用上下文Monad (State t s)不起作用:

Could not deduce (Monad (State t [Bool])) arising from a do statement from the context (Monad (State t s))

这更让我困惑。前者肯定是可以从后者还原的吗?)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-11 04:34:29

这是一个限制,但有一个很好的理由:如果它不能这样工作,那么预期的语义会是什么呢?

代码语言:javascript
复制
runState :: State t s a -> s -> (s,a)
runState (State f) s = f s

example :: s -> a
example = snd $ runState ((State undefined) >> return 1) ()

嗯,可能是

代码语言:javascript
复制
example = snd $ runState ((State undefined) >>= \_ -> return 1) ()
        = snd $ runState (State $ \s -> case undefined s of (s',_) -> (s',1)) ()
        = snd $ case undefined () of (s',_) -> (s',1)
        = snd $ case undefined of (s',_) -> (s',1)
        = snd undefined
        = undefined

也可能是

代码语言:javascript
复制
example = snd $ runState ((State undefined) >>= \_ -> return 1) ()
        = snd $ runState (State $ \s -> case undefined s of ~(s',_) -> (s',1)) ()
        = snd $ case undefined () of ~(s',_) -> (s',1)
        = snd $ (undefined,1)
        = 1

这些是不一样的。一种选择是定义一个额外的类函数,如

代码语言:javascript
复制
class IsStrictness t where
   bindState :: State t s a -> (a -> State t s b) -> State t s b

然后定义

代码语言:javascript
复制
instance IsStrictness t => Monad (State t s) where
   return = returnState
   (>>=) = bindState

而不是将bindState定义为IsStrictness的一部分,您可以使用单例

代码语言:javascript
复制
data SingStrictness (t :: Strictness) where
   SingStrict :: SingStrictness Strict
   SingLazy   :: SingStrictness Lazy

class IsStrictness t where
   singStrictness :: SingStrictness t

bindState :: IsStrictness t => State t s a -> (a -> State t s b) -> State t s b
bindState ma' amb' = go singStrictness ma' amb' where
  go :: SingStrictness t -> State t s a -> (a -> State t s b) -> State t s b
  go SingStrict ma amb = ...
  go SingLazy ma amb = ...

它可以使用GHC7.6中的单子基础结构来进一步增强,而不是使用自定义类和单例类型。你最终会

代码语言:javascript
复制
instance SingI t => Monad (State t s)

其实也没那么可怕。习惯于约束集中有大量的SingI _。这就是它的工作方式,至少有一段时间,而且没有那么丑陋。

关于为什么State t [Bool]不能从State t s中还原:问题是State t s在顶级上下文中,这意味着s是在最外层量化的。您正在定义一个函数,它说:“对于任何t和s,Monad (State T s)我将给您.”。但是,这并不意味着“我会给你.”。可悲的是,这些普遍量化的约束在Haskell并不是那么容易。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14269732

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档