Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中多态性的引用透明性_Haskell_Polymorphism_Referential Transparency_Higher Rank Types - Fatal编程技术网

Haskell中多态性的引用透明性

Haskell中多态性的引用透明性,haskell,polymorphism,referential-transparency,higher-rank-types,Haskell,Polymorphism,Referential Transparency,Higher Rank Types,假设我有一个函数: f :: Int -> (Rational, Integer) f b = ((toRational b)+1,(toInteger b)+1) 我想这样抽象出(+1): 这显然不起作用,但如果我指定类型签名,它将起作用: f :: Int -> (Rational, Integer) f b = (h (toRational b) ,h (toInteger b)) where h :: Num a => a -> a

假设我有一个函数:

f :: Int -> (Rational, Integer)
f b = ((toRational b)+1,(toInteger b)+1)
我想这样抽象出(+1):

这显然不起作用,但如果我指定类型签名,它将起作用:

f :: Int -> (Rational, Integer)
f b = (h (toRational b)
      ,h (toInteger b))
    where h :: Num a => a -> a
          h = (+1)
假设我现在想通过传递h作为参数来进一步抽象函数:

f :: Num a => Int -> (a -> a) -> (Rational, Integer)
f b g = (h (toRational b)
        ,h (toInteger b))
    where h :: Num a => a -> a
          h = g
我得到一个错误,内部的a和外部的a不一样

有人知道如何正确编写此函数吗? 我想将多态函数
g
传递给
f
,并以多态方式使用它


我已经在不同的项目中多次遇到这种情况,但我找不到一个好的解决方案。

我找到了解决方案:使用forall量词,如下所示:

{-# LANGUAGE RankNTypes #-}
f :: Int -> (forall a. Num a=> a -> a) -> (Rational, Integer)
f b g = (h (toRational b)
        ,h (toInteger b))
    where h :: Num a => a -> a
          h = g
这当然可以转化为:

f :: Int -> (forall a. Num a=>a -> a) -> (Rational, Integer)
f b g = (g (toRational b)
        ,g (toInteger b))

这是完全正确的。如果没有forall,Haskell将尝试在函数体中专门化函数参数。这导致了不可解系统
(Rational~a)和&(Integer~a)
。forall绑定表示您将传入一个未专门化的函数,并仅在调用站点专门化它。缺点是,您无法传递另一个
a
输入,并确保它与函数匹配,而不是在这种情况下您会这样做。欢迎来到排名更高的类型世界!“这显然行不通”事实上,这行不通并不明显:
(+1)
是多态的,只有
h
阻止了这一特性的继承。如果设置
-XNoMonomorphismRestriction
,则第二个代码框工作正常。
f :: Int -> (forall a. Num a=>a -> a) -> (Rational, Integer)
f b g = (g (toRational b)
        ,g (toInteger b))