Haskell 无法使用单例库将类型级别列表转换回值级别
我正在尝试编写一个经过合理静态检查的授权系统[1],目前正在努力编写一个函数,将所需权限从类型级注释/幻影提取到值级Haskell 无法使用单例库将类型级别列表转换回值级别,haskell,singleton,data-kinds,Haskell,Singleton,Data Kinds,我正在尝试编写一个经过合理静态检查的授权系统[1],目前正在努力编写一个函数,将所需权限从类型级注释/幻影提取到值级 {-# LANGUAGE DataKinds, GADTs, ScopedTypeVariables #-} module Try5 where import Control.Monad.Reader import Data.Singletons import Data.Singletons.TH data Permission = PermA
{-# LANGUAGE DataKinds, GADTs, ScopedTypeVariables #-}
module Try5 where
import Control.Monad.Reader
import Data.Singletons
import Data.Singletons.TH
data Permission = PermA
| PermB
deriving (Eq, Show)
$(genSingletons [''Permission])
data Env = Env
newtype AppM (perms :: [Permission]) a = AppM (ReaderT Env IO a) deriving (Functor, Applicative, Monad, MonadIO, MonadReader Env)
-- other functions for constructing an action in `AppM perms`
-- have been removed for brevity
runAction :: AppM (perms :: [Permission]) () -> IO ()
runAction _ = do
let permissions :: [Permission] = fromSing $ singByProxy (Proxy :: Proxy (perms :: [Permission]))
putStrLn $ "Huzzah, I freed the permissions from the type-level cage: " <> (show permissions)
pure ()
[1] 更多上下文可在
perms中找到不在运行操作的主体中。它需要显式地与所有
绑定。看
另一个问题是,要从类型中“降级”值,需要一个SingI
实例
关键的直觉是,forall
引入了与运行时无关的变量:ifrunAction::forall p
没有任何约束,runAction@p
实际上不能依赖于p
的值,它必须始终执行相同的操作。理查德·艾森伯格(Richard Eisenberg)的论文中有关于这一问题的更多细节(第4.2节)
因此,runAction
的类型应该是这样的:
runAction :: forall perms. SingI perms => AppM perms () -> IO ()
还请注意,使用此更正的签名,您可以使用Data.singleton.Prelude.List
中的SList
编写let permissions=fromSing(sing::SList perms)
,甚至只需fromSing(sing::sing perms)
。关键是您不需要单独的代理。singix
约束的直觉是什么?一个类型(或种类?)为它定义了单例?还有,为什么sing::sing perms
有效,而sing@perms
无效?另一方面,它似乎在一个代码片段中工作,看起来约束是一个隐式参数(具有一致性属性:没有两个相同类型的值可以通过这种方式传递)。从这个角度来看,SingI x
是一个Sing x
值(您可以通过Sing
访问该值)。试试sing@@perms
<代码>歌唱
是多种类的。i、 例如,perms
可以是任何类型,而类型应用程序将这种类型作为一个参数进行了明确说明(我相信有人建议改变这种怪癖)。
runAction :: forall perms. SingI perms => AppM perms () -> IO ()