有没有办法在没有将类型包装到某种辅助容器中的情况下实现这样的东西?
class TestClass a where
returnInt :: a -> Int
data TestData0 = TestData0
data TestData1 = TestData1
instance TestClass TestData0 where
returnInt _ = 0
instance TestClass TestData1 where
returnInt _ = 1
testisFunction :: (TestClass a) => Int -> a
testisFunction 0 = TestData0
testisFunction 1 = TestData1
答案 0 :(得分:4)
正如之前在其他问题中所回答的那样,您可以使用存在性包装器:
{-# LANGUAGE ExistentialTypes #-}
data SomeTest = forall a. TestClass a => SomeTest a
instance TestClass SomeTest where
returnInt (SomeTest t) = returnInt t
testFunction :: Int -> SomeTest
testFunction 0 = SomeTest TestData0
testFunction 1 = SomeTest TestData1
然后用法是:
returnInt (testFunction 0) == 0
但是,在回答您的具体问题时, 可以通过延续传递样式将代码“内外”转换为()来转换( rank-1)存在类型为(rank-2)通用类型:
{-# LANGUAGE RankNTypes #-}
testFunction :: Int -> (forall a. TestClass a => a -> r) -> r
testFunction 0 k = k TestData0
testFunction 1 k = k TestData1
然后我们传递一个接受其结果的函数,而不是消耗testFunction
的结果。至关重要的是,此函数必须有效forall a. TestClass a
,因此它不知道a
类型的任何内容,除了它是TestClass
的实例。用法更改为:
testFunction 0 returnInt == 0
请注意,顶级forall
隐含在类型签名中,因此这表示testFunction
的来电者决定a
是什么:
testFunction :: TestClass a => Int -> a
testFunction :: forall a. TestClass a => Int -> a
这种类型相当于:
testFunction :: Int -> (forall a. TestClass a => a)
向内移动forall
一个级别,因此它适用于续篇k
,表示testFunction
的调用方k
现在决定a
是的。 testFunction
的来电者现在通过传递特定的r
来决定k
(结果类型)。
testFunction :: forall r. Int -> (forall a. TestClass a => a -> r) -> r
答案 1 :(得分:0)
不,你需要某种包装。