Haskell返回类型多态与类限制

时间:2017-06-10 18:43:37

标签: haskell polymorphism return-type

有没有办法在没有将类型包装到某种辅助容器中的情况下实现这样的东西?

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

2 个答案:

答案 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)

不,你需要某种包装。