[英]How to cast `forall a. a -> a` back to `a -> a`?
In my actual problem I have a function f
, passed as a parameter, that changes the order in a list but has no requirements regarding type and does not change the type either.在我的实际问题中,我有一个函数
f
,作为参数传递,它改变了列表中的顺序,但对类型没有要求,也不改变类型。 I want to apply that function on [Int]
and [Bool]
so I have to resolve both contexts trying to typecast f
to either [Int] -> [Int]
or [Bool] -> [Bool]
.我想在
[Int]
和[Bool]
上应用该函数,所以我必须解决试图将f
类型转换为[Int] -> [Int]
或[Bool] -> [Bool]
两个上下文。 I solved this with Rank2Types
.我用
Rank2Types
解决了这个Rank2Types
。 But then I use any
on a list of functions like f
and any
requires the functions to be [a] -> [a]
rather than forall a. [a] -> [a]
但是随后我在
f
等函数列表中使用any
,并且any
要求函数为[a] -> [a]
而不是forall a. [a] -> [a]
forall a. [a] -> [a]
. forall a. [a] -> [a]
。
The code below while nonsensical perfectly reproduces the error:下面的代码虽然荒谬,但完美地重现了错误:
{-# LANGUAGE Rank2Types #-}
--debug :: (forall a. [a] -> [a]) -> Bool
debug swap = any combine [swap]
where
combine :: (forall a. [a] -> [a]) -> Bool
combine f = usefonBool f && usefonInt f
--usefonBool :: (forall a. [a] -> [a]) -> Bool
usefonBool f = f [True,True] == [False]
--usefonInt :: (forall a. [a] -> [a]) -> Bool
usefonInt f = (f [1,2]) == [2,1]
The error message is:错误信息是:
• Couldn't match type ‘a’ with ‘forall a1. [a1] -> [a1]’
‘a’ is a rigid type variable bound by
the inferred type of debug :: a -> Bool
at /path/debug.hs:(4,1)-(12,36)
Expected type: a -> Bool
Actual type: (forall a. [a] -> [a]) -> Bool
• In the first argument of ‘any’, namely ‘combine’
In the expression: any combine [swap]
In an equation for ‘debug’:
debug swap
= any combine [swap]
where
combine :: (forall a. [a] -> [a]) -> Bool
combine f = usefonBool f && usefonInt f
usefonBool f = f [True, ....] == [False]
usefonInt f = (f [1, ....]) == [2, ....]
• Relevant bindings include
swap :: a (bound at /path/debug.hs:4:7)
debug :: a -> Bool (bound at /path/debug.hs:4:1)
|
My goal is to find an annotation that lets me use an f
on different types and then apply any on a list of such generic functions.我的目标是找到一个注释,让我可以在不同类型上使用
f
,然后将 any 应用于此类通用函数的列表。
If I uncomment all my type annotations (or just the top one) the error changes to如果我取消注释所有类型注释(或只是顶部注释),错误将更改为
• Couldn't match type ‘[a0] -> [a0]’ with ‘forall a. [a] -> [a]’
Expected type: ([a0] -> [a0]) -> Bool
Actual type: (forall a. [a] -> [a]) -> Bool
• In the first argument of ‘any’, namely ‘combine’
In the expression: any combine [swap]
In an equation for ‘debug’:
debug swap
= any combine [swap]
where
combine :: (forall a. [a] -> [a]) -> Bool
combine f = usefonBool f && usefonInt f
usefonBool :: (forall a. [a] -> [a]) -> Bool
usefonBool f = f [True, ....] == [False]
....
|
First, note that Rank2Types
is a deprecated name.首先,请注意
Rank2Types
是一个已弃用的名称。 It's equivalent to RankNTypes
in modern GHC, and that's the preferred name for the extension.它相当于现代 GHC 中的
RankNTypes
,这是扩展的首选名称。
Here's the underlying problem.这是根本的问题。 A "list of such generic functions" could have the type:
“此类通用函数的列表”可以具有以下类型:
[forall a. [a] -> [a]]
Sadly, this isn't a valid Haskell type because Haskell doesn't support "impredicative polymorphism".遗憾的是,这不是有效的 Haskell 类型,因为 Haskell 不支持“不可预测的多态性”。 Specifically, the following program:
具体来说,以下程序:
{-# LANGUAGE RankNTypes #-}
myFunctions :: [forall a. [a] -> [a]]
myFunctions = [f1, f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
produces the error message:产生错误信息:
DebugRank.hs:2:16: error: • Illegal polymorphic type: forall a. [a] -> [a] GHC doesn't yet support impredicative polymorphism • In the type signature: myFunctions :: [forall a. [a] -> [a]]
There's an extension, ImpredicativeTypes
.有一个扩展,
ImpredicativeTypes
。 It's flakey and incomplete, but it allows the following to compile:它不完整且不完整,但它允许编译以下内容:
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ImpredicativeTypes #-}
myFunctions :: [forall a. [a] -> [a]]
myFunctions = [f1, f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [forall a. [a] -> [a]] -> Bool
debug = any combine
where
combine :: (forall a. [a] -> [a]) -> Bool
combine f = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
main = print (debug myFunctions)
I'd still recommend against using it, though.不过,我仍然建议不要使用它。
The usual alternative is to use a newtype
wrapper for the polymorphic function:通常的替代方法是对多态函数使用
newtype
包装器:
newtype ListFunction = ListFunction (forall a. [a] -> [a])
This requires some boilerplate, but no extensions other than RankNTypes
:这需要一些样板,但除了
RankNTypes
之外没有扩展:
myFunctions :: [ListFunction]
myFunctions = [ListFunction f1, ListFunction f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [ListFunction] -> Bool
debug = any combine
where
combine :: ListFunction -> Bool
combine (ListFunction f) = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
The complete code:完整代码:
{-# LANGUAGE RankNTypes #-}
newtype ListFunction = ListFunction (forall a. [a] -> [a])
myFunctions :: [ListFunction]
myFunctions = [ListFunction f1, ListFunction f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [ListFunction] -> Bool
debug = any combine
where
combine :: ListFunction -> Bool
combine (ListFunction f) = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
main = print $ debug myFunctions
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.