Haskell ImpIndicativeTypes的简单示例
《GHC用户指南》参考以下示例介绍了:Haskell ImpIndicativeTypes的简单示例,haskell,impredicativetypes,Haskell,Impredicativetypes,《GHC用户指南》参考以下示例介绍了: f :: Maybe (forall a. [a] -> [a]) -> Maybe ([Int], [Char]) f (Just g) = Just (g [3], g "hello") f Nothing = Nothing 但是,当我在文件中定义此示例并尝试调用它时,会出现一个类型错误: ghci> f (Just reverse) <interactive>:8:9: Couldn't match ex
f :: Maybe (forall a. [a] -> [a]) -> Maybe ([Int], [Char])
f (Just g) = Just (g [3], g "hello")
f Nothing = Nothing
但是,当我在文件中定义此示例并尝试调用它时,会出现一个类型错误:
ghci> f (Just reverse)
<interactive>:8:9:
Couldn't match expected type `forall a. [a] -> [a]'
with actual type `[a0] -> [a0]'
In the first argument of `Just', namely `reverse'
In the first argument of `f', namely `(Just reverse)'
In the expression: f (Just reverse)
ghci> f (Just id)
<interactive>:9:9:
Couldn't match expected type `forall a. [a] -> [a]'
with actual type `a0 -> a0'
In the first argument of `Just', namely `id'
In the first argument of `f', namely `(Just id)'
In the expression: f (Just id)
ghci>f(刚好相反)
:8:9:
无法匹配所有a的预期类型。[a] ->[a]'
实际类型为“[a0]->[a0]”
在'Just'的第一个参数中,即'reverse'
在“f”的第一个参数中,即“刚好相反”
在表达式中:f(正好相反)
ghci>f(仅id)
:9:9:
无法匹配所有a的预期类型。[a] ->[a]'
实际类型为'a0->a0'
在'Just'的第一个参数中,即'id'
在'f'的第一个参数中,即`(Just id)'
在表达式中:f(仅id)
似乎只有未定义
,无
,或仅未定义
满足类型检查器的要求
因此,我有两个问题:
- 对于任何非底部的
,是否可以使用f
调用上述函数Just f
- 是否有人能提供一个仅可使用非指示多态性定义的值的示例,并以非平凡的方式使用
justForF :: (forall a. [a] -> [a]) -> Maybe (forall a. [a] -> [a])
justForF = Just
ghci> f (justForF reverse)
Just ([3],"olleh")
或者这个(基本上是内联的):
在您的案例中,类型推断似乎在推断的类型时有问题,我们必须告诉它类型
我不知道这是否是一个bug,也不知道这是否有充分的理由……) ghc-7+中新的typechecker不是已经悄悄地删除了ImpredicativeTypes
?请注意,ideone.com仍然使用ghc-6.8,事实上,您的程序使用它可以正常运行:
{-# OPTIONS -fglasgow-exts #-}
f :: Maybe (forall a. [a] -> [a]) -> Maybe ([Int], [Char])
f (Just g) = Just (g [3], g "hello")
f Nothing = Nothing
main = print $ f (Just reverse)
按预期打印([3],“olleh”)
;看
augustss
给出了一个很好的用例——某种模仿Python dsl的方式——并对这里的扩展进行了辩护:在这里的票证中提到了一个例子,说明了一个项目如何使用ImpredicativeTypes
来指定匹配规则的列表
其思想是,当我们有一个形式为App(PrimOp nameStr)(Lit litVal)
的表达式时,我们希望根据PrimOp名称查找适当的规则。litVal
将是MachFloat d
或MachFloat d
(d
是Rational
)。如果我们找到一条规则,我们希望将该规则的函数应用于转换为正确类型的d
函数mkunaryclapseiee
对一元函数执行此操作
mkUnaryCollapseIEEE :: (forall a. RealFloat a => (a -> a))
-> Opts
-> CoreExpr
-> CoreM CoreExpr
mkUnaryCollapseIEEE fnE opts expr@(App f1 (App f2 (Lit lit)))
| isDHash f2, MachDouble d <- lit = e d mkDoubleLitDouble
| isFHash f2, MachFloat d <- lit = e d mkFloatLitFloat
where
e d = evalUnaryIEEE opts fnE f1 f2 d expr
如果样板太多,不合我的口味,这没关系
但是,有一个类似的函数mkunaryclapseprimiee
。在这种情况下,不同GHC版本的规则是不同的。如果我们想支持多个GHC,这会有点棘手。如果我们采用相同的方法,那么subs
定义将需要大量的CPP,这可能无法维护。相反,我们在单独的文件中为每个GHC版本定义了规则。但是,由于循环导入问题,mkunaryclapseprimiee
在这些模块中不可用。我们可能会重新构造模块以使其工作,但我们将规则集定义为:
unaryPrimRules :: [(String, (forall a. RealFloat a => a -> a))]
unaryPrimRules =
[ ("GHC.Prim.expDouble#" , exp)
, ("GHC.Prim.logDouble#" , log)
-- lines omitted
, ("GHC.Prim.expFloat#" , exp)
, ("GHC.Prim.logFloat#" , log)
]
通过使用ImpredicativeTypes
,我们可以保留一个秩2函数的列表,用于mkunaryclapseprimiree
的第一个参数。替代方案将是更多的CPP/样板,更改模块结构(或循环导入),或大量代码复制。这些我都不喜欢
我确实记得GHC总部表示他们想放弃对扩展的支持,但也许他们已经重新考虑了。它有时很有用。很有趣。对所有a来说,是可以接受的。[a] ->[a]
<代码>全部a。可能([a]->[a])
失败,因为类型检查器似乎试图将a
实例化为Int
和Char
<代码>可能(对于所有a.[a]->[a])失败,因为它需要对于所有a。[a] ->[a]
,但它得到一个[a0]->[a0]
,其中a0
是新的。因此,使用Maybe
,嵌套类型方案只实例化一次,但是没有Maybe
,一切都很好。谢谢,这很有趣!我已经尝试过注释反向
,但现在回想起来,这是行不通的。不过,我还不会接受这个答案,因为这个解决方案有点恶心:预测多态性不能很好地处理HM样式的类型。在某种意义上,通用类型是用Haskell和类似的语言自动“打开”的。也就是说,类型变量是在最外层量化的。f
需要impindicativetypes
来编译(如果我只给出RankNTypes
,GHC甚至建议扩展),因此它肯定没有被完全删除。是的,如果您尝试语法,它会立即要求您使用扩展(对于所有a.[a]->[a])
,就像以前一样;但是它忽略了签名的简单含义,除了一些残留的情况。我有一些代码使用ImpredicativeTypes
来实现规则:[(字符串,(对于所有a.RealFloat a=>a->a))]
,与ghc-7.6配合使用效果很好。备选方案似乎不太吸引人。@约翰:如果你想发布一个简短的摘要,这实际上可以回答我的第二个问题。莱纳特a的讨论不是回答了你的第二个问题吗?约翰L的函数修订很好g:[(Int,对于所有a.->[a])->可能([Int],[Char]);g[]=Nothing;g((n,ff):nfs)=Just(ff[3],ff“hello”)
我的想法是您不想依赖它在ghc-7中工作。现在我的问题的两部分都得到了回答,但不幸的是,两个答案并不相同:)我明白了
unarySubIEEE :: String -> (forall a. RealFloat a => a -> a) -> CMSub
unarySubIEEE nm fn = CMSub nm (mkUnaryCollapseIEEE fn)
subs =
[ unarySubIEEE "GHC.Float.exp" exp
, unarySubIEEE "GHC.Float.log" log
, unarySubIEEE "GHC.Float.sqrt" sqrt
-- lines omitted
, unarySubIEEE "GHC.Float.atanh" atanh
]
unaryPrimRules :: [(String, (forall a. RealFloat a => a -> a))]
unaryPrimRules =
[ ("GHC.Prim.expDouble#" , exp)
, ("GHC.Prim.logDouble#" , log)
-- lines omitted
, ("GHC.Prim.expFloat#" , exp)
, ("GHC.Prim.logFloat#" , log)
]