Referential transparency with polymorphism in Haskell

我的未来我决定 提交于 2019-12-06 17:12:21

问题


Say I have a function:

f :: Int -> (Rational, Integer)
f b = ((toRational b)+1,(toInteger b)+1)

I want to abstract away the (+1) like so:

f :: Int -> (Rational, Integer)
f b = (h (toRational b)
      ,h (toInteger b))
    where h = (+1)

This wont work obviously, but if I specify the type signature it will work:

f :: Int -> (Rational, Integer)
f b = (h (toRational b)
      ,h (toInteger b))
    where h :: Num a => a -> a
          h = (+1)

Say I now want to further abstract the function by passing h as a parameter:

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

I get an error that the inner a is not the same a as the outer one.

Does anyone know how to write this function correctly? I want to pass a polymorphic function g to f and use it polymorphically.

I have encountered this situation multiple times now in very different projects, and I could not find a good solution.


回答1:


I found the solution: using the forall quantifier like so:

{-# 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

Which of course can be turned into:

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


来源:https://stackoverflow.com/questions/14865734/referential-transparency-with-polymorphism-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!