Haskell ImpIndicativeTypes的简单示例

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

《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 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)
    ]