我下面的例子中列明的问题Can I have an unknown KnownNat?结合`SomeNat`和`Nat`
我想作一个小改动的代码。
原始代码是
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
import GHC.TypeLits
import Data.Proxy
data Bar (n :: Nat) = Bar String deriving Show
bar :: (KnownNat n) => Bar n -> (String, Integer)
bar [email protected](Bar s) = (s, natVal b)
main :: IO()
main = do
i <- readLn
let Just someNat = someNatVal i
case someNat of
SomeNat (_ :: Proxy n) -> do
let a :: Bar n
a = Bar "as"
print $ bar a
预期其工作。我想修改其中的类型级别n
。
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
import GHC.TypeLits
import Data.Proxy
data Bar (n :: Nat) = Bar String deriving Show
bar :: (KnownNat n) => Bar n -> (String, Integer)
bar [email protected](Bar s) = (s, natVal b)
main :: IO()
main = do
i <- readLn
let Just someNat = someNatVal i
case someNat of
SomeNat (_ :: Proxy n) -> do
let a :: Bar (n + 5)
a = Bar "as"
print $ bar a
该错误消息我得到的是
Could not deduce (KnownNat (n + 5)) arising from a use of ‘bar’
from the context (KnownNat n)
bound by a pattern with constructor
SomeNat :: forall (n :: Nat). KnownNat n => Proxy n -> SomeNat,
in a case alternative
at Blag.hs:19:9-30
In the second argument of ‘($)’, namely ‘bar a’
In a stmt of a 'do' block: print $ bar a
In the expression:
do { let a :: Bar (n + 5)
a = Bar "as";
print $ bar a }
Failed, modules loaded: none.
为什么不能编译器推断出KnownNat n
KnownNat (n + 5)
?
我的猜测是GHC无法将n + 5减少为任何类型的正常形式,并且因为它不能查找类型实例 - 因为它不知道它在找什么!在不知道n是什么的情况下,对n + 5的评价无法进行(假设通过左边的论证进行归纳定义的典型问题)。我不太了解KnownNat如何工作背后的魔力,但它可能只知道如何找到该实例,如果它给了一个具体的类型。 – ocharles
如果知道'n',GHC就不知道'n + 5'是已知的。已知的唯一'Nat'表达式是数字文字。另一方面,如果您在类型级别上使用自定义一元数字,并且以归纳方式实现已知性和附加性,则可能会导致更多的事实对GHC显而易见,包括所涉及的含义。 –
如果已知的唯一'Nat'表达式是数字文字,那么第一个示例如何工作? – Alpaca