这是一个简化的示例,显示了我得到的错误,我不明白。它还有点长,对不起。
--
-- Test of XMaybe and XMonad
--
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Main (main) where
-------------------------------------------------------------------------------
class XMonad (tc :: k -> * -> *) (af :: k) (bf :: k) where
type XResultT tc af bf :: k
(>>~) :: tc af a -> (a -> tc bf b) -> tc (XResultT tc af bf) b
-------------------------------------------------------------------------------
data XMaybe :: Bool -> * -> * where
XNothing :: XMaybe False a
XJust :: a -> XMaybe True a
instance XMonad XMaybe False False where
type XResultT XMaybe False False = False
(>>~) _ _ = XNothing
instance XMonad XMaybe True False where
type XResultT XMaybe True False = False
(>>~) _ _ = XNothing
instance XMonad XMaybe False True where
type XResultT XMaybe False True = False
(>>~) _ _ = XNothing
instance XMonad XMaybe True True where
type XResultT XMaybe True True = True
(>>~) (XJust x) f = f x
-------------------------------------------------------------------------------
fromXMaybe :: XMaybe t a -> Maybe a
fromXMaybe (XJust x) = Just x
fromXMaybe XNothing = Nothing
-------------------------------------------------------------------------------
class TestClass a where
type Enabled a :: Bool
queryVal :: a -> XMaybe (Enabled a) Int
queryGet :: a -> XMaybe (Enabled a) (a -> Int)
-------------------------------------------------------------------------------
newtype Test = Test Int deriving Show
instance TestClass Test where
type Enabled Test = True
queryVal (Test x) = XJust x
queryGet _ = XJust (\(Test x) -> x)
-------------------------------------------------------------------------------
test :: (TestClass a, Show a) => a -> IO ()
test x0 = do
putStrLn "--------------------"
putStr " x0 = "
print x0
-- This is OK
let x1 = queryVal x0
putStr " x1 = "
print $ fromXMaybe x1
-- This is OK
let x2 = queryGet x0
-- This gives a compiler error - (Enabled a) isn't evaluated, so the
-- instance of XMonad is undetermined, so >>~ is rejected. But AFAICT that
-- (Enabled a) *should* be evaluated - which TestClass instance doesn't seem
-- ambiguous...
--
-- 1. The instance specifies "type Enabled Test = True"
-- 2. If it was ambiguous, how come the earlier queryGet call works fine?
-- Comment out the following two lines and this compiles and runs. Isn't
-- an ambiguous result type automatically a compile-time error?
--
let x3 = queryGet x0 >>~ \get ->
XJust $ get x0
putStrLn "--------------------"
-------------------------------------------------------------------------------
main :: IO ()
main = test (Test 3)
-------------------------------------------------------------------------------
以下是GHC 7.10.3 ......
的具体错误[1 of 1] Compiling Main ( test03.hs, test03.o )
test03.hs:91:24:
Could not deduce (XMonad XMaybe (Enabled a) 'True)
arising from a use of ‘>>~’
from the context (TestClass a, Show a)
bound by the type signature for
test :: (TestClass a, Show a) => a -> IO ()
at test03.hs:67:9-43
In the expression: queryGet x0 >>~ \ get -> XJust $ get x0
In an equation for ‘x3’:
x3 = queryGet x0 >>~ \ get -> XJust $ get x0
In the expression:
do { putStrLn "--------------------";
putStr " x0 = ";
print x0;
let x1 = queryVal x0;
.... }
基本上,由于尚未评估关联类型,因此尚未推断出类实例。但是,触发问题的>>~
运算符只是从第一个参数中获取该类型信息。相同的关联类型似乎只对完全相同的类型进行了评估,从queryVal
和queryGet
确定结果类型,只要该结果不作为第一个参数传递给{{ 1}}。
从一些乱七八糟的东西我不久前使用类型级自然功能,我感觉我的>>~
函数缺少一个约束 - 类似于test
- 但是到目前为止我不能说这个存在。
那么 - 我做错了什么?
来自何处的说明 - KnownBool (Enabled a)
与XMaybe
类似,但具有静态解析的类型级知识,即Maybe
或XJust
是否适用。它可以是XNothing
实例,所有法律都受到尊重,它应该消除所有混乱,但它不像Monad
那样工作 - 顺序操作必须全部{{1或者所有Maybe
,因此混合将是类型错误而不是XJust
结果。所以XNothing
是一个monad-ish类,它允许一个额外的类型参数变化,XNothing
是一个bind-ish运算符。由于歧义问题,没有相应的XMonad
- 现在我只是使用>>~
构造函数。
由于只有一个实例,return
类可能是多余的,并且当然需要更加通用(尽管缺少XJust
打破了这种普遍性),但我想要看看类型变化的monadish-things旅程结束的地方 - 可能是IxMonad,可能有类似但略有不同的东西,尽管目前我对XMonad
的了解不多于return
存在。
与此同时,我陷入了这个编译错误。
根据以下@dfeuer的回答和评论,但未使用IxMonad
解决方案,因为我认为KnownBool
无论如何应该知道XMaybe
...
Bool
答案 0 :(得分:2)
问题是GHC指出的。 test
中的a
是多态的,因此在测试中无法确定Enabled a
实际上是什么,因此无法选择{ {1}}实例。你也没有XMonad
约束来抽象它,因此它不会编译。你可以很容易地使用那种已知的XMonad
"你提到:
Bool
添加这样的上下文可以让您在data SBool (b :: Bool) where
SFalse :: SBool 'False
STrue :: SBool 'True
class KnownBool (b :: Bool) where
knownBool :: SBool b
instance KnownBool 'False where
knownBool = SFalse
instance KnownBool 'True where
knownBool = STrue
上进行模式匹配,以显示knownBool
类型参数,从而显示相应的Bool
实例。你甚至可以使用两个XMonad
约束为所有可能的东西编写一个XMonad
实例。
如果您永远不会使用某个参数,请将其设为代理:
KnownBool
这样可以更轻松地调用class TestClass a where
type Enabled a :: Bool
queryVal :: a -> XMaybe (Enabled a) Int
queryGet :: proxy a -> XMaybe (Enabled a) (a -> Int)
函数。
即使你想要queryGet
的多个实例(我能想到的主要原因是获得某些内联行为),你仍然可以减少它们的数量:
XMonad