Till now, I assumed, that GHC executes a type level function (type-family) at compile time. Therefore an error message triggered by the TypeError type-family should be issued at compile-time.
In the following example, I get the type error at run time.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
import GHC.TypeLits
type family If c t e where
If 'True t e = t
If 'False t e = e
type family EqSymbol (a :: Symbol) (b :: Symbol) where
EqSymbol a a = 'True
EqSymbol a b = 'False
type family Lookup (x :: Symbol) (l :: [(Symbol,t)]) :: t where
Lookup k '[] = TypeError (Text "Key not found: " :<>: Text k)
Lookup k ('(x,a) ': ls) = If (EqSymbol k x) a (Lookup k ls)
type TList = '[ '("foo", Int), '("bar", String)]
test1 :: Lookup "foo" TList
test1 = undefined
test2 :: Lookup "bar" TList
test2 = undefined
test3 :: Lookup "baz" TList
test3 = undefined
For the function test3
the evaluation of the type-level function Lookup
should give a type error, because baz is not a key in TList
.
GHCi loads the code without a type-error:
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> :l SO.hs
[1 of 1] Compiling Main ( SO.hs, interpreted )
Ok, modules loaded: Main.
Querying the types of the functions test1
, test2
gives the exepected results:
*Main> :t test1
test1 :: Int
*Main> :t test2
test2 :: [Char]
Querying the type of the function test3 gives a type error and the TypeError function is only executed when I try to evaluate the test3
function:
*Main> :t test3
test3 :: (TypeError ...)
*Main> test3
<interactive>:5:1: error:
• Key not found: baz
• When checking the inferred type
it :: (TypeError ...)
What do I have to do, to get a compile-time error?
The reason this doesn't cause an error when compiling your module is lazyness. It's basically the same reason that print (if True then 1 else error "Mearg")
doesn't cause any problems: because the else
branch is never actually used , there is (provably!) no way the error-raising expression could influence the result. If you will, the error only happens in an alternative universe.
Likewise, you never make any use of the type information that test3
could (well, not-!) supply. Ie you never evaluate the Lookup "baz" TList
result, not at compile-time nor at runtime. So there is no error!
In any real program using such a type family, you would however be interested in concrete type information, and do things like
show0 :: (Show q, Num q) => q -> String
show0 q = show $ 0`asTypeOf`q
main :: IO ()
main = putStrLn $ show0 test3
And that does cause a compile-time error (twice in fact, for some reason):
sagemuej@sagemuej-X302LA:~$ ghc /tmp/wtmpf-file2798.hs
[1 of 1] Compiling Main ( /tmp/wtmpf-file2798.hs, /tmp/wtmpf-file2798.o )
/tmp/wtmpf-file2798.hs:35:19: error:
• Key not found: baz
• In the second argument of ‘($)’, namely ‘show0 test3’
In the expression: putStrLn $ show0 test3
In an equation for ‘main’: main = putStrLn $ show0 test3
|
35 | main = putStrLn $ show0 test3
| ^^^^^^^^^^^
/tmp/wtmpf-file2798.hs:35:19: error:
• Key not found: baz
• In the second argument of ‘($)’, namely ‘show0 test3’
In the expression: putStrLn $ show0 test3
In an equation for ‘main’: main = putStrLn $ show0 test3
|
35 | main = putStrLn $ show0 test3
| ^^^^^^^^^^^
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.