[英]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.