简体   繁体   English

具有类限制的Haskell返回类型多态

[英]Haskell return type polymorphism with class restriction

Is there a way to achieve something like this without wrapping types in some kind of helper container? 有没有一种方法可以在不将类型包装在辅助容器中的情况下实现这种目的?

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

As has been answered in other questions before, you can use an existential wrapper: 就像之前在其他问题中已经回答的那样,您可以使用存在性包装器:

{-# 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

Then the usage is: 然后的用法是:

returnInt (testFunction 0) == 0

However, in answer to your specific question, it is possible to avoid this wrapper by turning your code “inside out” with continuation-passing style , converting the (rank-1) existential type into a (rank-2) universal type: 然而,在回答您的具体问题, 可以通过与延续传递风格转向代码“内而外”,转换(等级1)存在类型为(等级2)普及型来避免这个包装:

{-# LANGUAGE RankNTypes #-}

testFunction :: Int -> (forall a. TestClass a => a -> r) -> r
testFunction 0 k = k TestData0
testFunction 1 k = k TestData1

Then instead of consuming the result of testFunction , we pass a function that will accept its result. 然后,我们传递一个将接受其结果的函数,而不是消耗testFunction的结果。 Crucially, this function must work forall a. TestClass a 至关重要的是,此功能必须全部起作用forall a. TestClass a forall a. TestClass a , so it doesn't know anything about the type a other than that it's an instance of TestClass . forall a. TestClass a ,因此除了它是TestClass的实例外,对类型a毫无了解。 The usage changes to: 用法更改为:

testFunction 0 returnInt == 0

Remember, top-level forall is implicit in type signatures, so this says that the caller of testFunction decides what a is: 请记住,顶级的forall在类型签名中是隐式的,因此这表示testFunction的调用者确定a是什么:

testFunction ::           TestClass a => Int -> a
testFunction :: forall a. TestClass a => Int -> a

And that type is equivalent to this: 该类型等效于此:

testFunction ::           Int -> (forall a. TestClass a => a)

Moving the forall one level inward, so it applies to the continuation k , means that testFunction , the caller of k , now decides what a is. 移动forall内一个水平,所以它适用于持续k ,意味着testFunction ,调用者k ,现在决定什么a是。 The caller of testFunction now decides what r (the result type) is by passing in a particular k . 现在, testFunction的调用者通过传入特定的k确定r (结果类型)是什么。

testFunction :: forall r. Int -> (forall a. TestClass a => a -> r) -> r

不,您需要某种包装纸。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM