Haskell 无法使用单例库将类型级别列表转换回值级别

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

我正在尝试编写一个经过合理静态检查的授权系统[1],目前正在努力编写一个函数,将所需权限从类型级注释/幻影提取到值级

{-# 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
引入了与运行时无关的变量:if
runAction::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 ()