幽灵和代理 - 导致幽灵般的错误

时间:2017-06-01 11:31:14

标签: haskell proxy phantom-types

我正在开发一个项目,我通过一个幻像类型跟踪我使用的db-schema - 它有一个KnownSymbol - 这是模式名称。

就在前几天,我遇到了以下问题 - 我不明白:

为什么无法定义withoutProxy或重新定义它?为什么GHC认为test属于*而非Symbol (Proxy :: Proxy test) ,虽然类型签名另有说明,但ScopedTypeVariables已启用。

{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures      #-}
module T where

import GHC.TypeLits
import Data.Proxy

newtype Phantom (x :: Symbol) y = Phantom y

withProxy :: (KnownSymbol test) => Proxy test -> Phantom test ()
withProxy _ = Phantom ()

withoutProxy :: (KnownSymbol test) => Phantom test ()
withoutProxy = withProxy (Proxy :: Proxy test)

我得到的错误最令人困惑

> ghci test.hs
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling T                ( test.hs, interpreted )

test.hs:14:27: error:
    • Couldn't match type ‘*’ with ‘Symbol’
      Expected type: Proxy test
        Actual type: Proxy test
      Use -fprint-explicit-kinds to see the kind arguments
    • In the first argument of ‘withProxy’, namely
        ‘(Proxy :: Proxy test)’
      In the expression: withProxy (Proxy :: Proxy test)
      In an equation for ‘withoutProxy’:
          withoutProxy = withProxy (Proxy :: Proxy test)
Failed, modules loaded: none.

然后启用-fprint-explicit-kinds

Prelude> :set -fprint-explicit-kinds 
Prelude> :r
[1 of 1] Compiling T                ( test.hs, interpreted )

test.hs:15:27: error:
    • Couldn't match type ‘*’ with ‘Symbol’
      Expected type: Proxy Symbol test
        Actual type: Proxy * test
    • In the first argument of ‘withProxy’, namely
        ‘(Proxy :: Proxy test)’
      In the expression: withProxy (Proxy :: Proxy test)
      In an equation for ‘withoutProxy’:
          withoutProxy = withProxy (Proxy :: Proxy test)
Failed, modules loaded: none.

1 个答案:

答案 0 :(得分:5)

简短回答:添加forall

withoutProxy :: forall test. (KnownSymbol test) => Phantom test ()
withoutProxy = withProxy (Proxy :: Proxy test)

第二行没有test,与上面的那个不同。

或者,根本不要添加类型注释:

withoutProxy :: (KnownSymbol test) => Phantom test ()
withoutProxy = withProxy Proxy

或者您可以添加{-# LANGUAGE PolyKinds #-},然后事情也会统一,因为Proxy :: Proxy test将是forall k (test :: k). Proxy k test,其中k是一种。