具有多种参数类型的多态输入函数

Polymorphic input function with multiple argument types

出于纯粹的好奇心,我想知道在 Haskell 中可能会出现类似以下的情况: 函数 foo 将另一个函数作为参数,该函数在 foo 的主体中多次调用,并在此过程中更改参数的类型。

以下代码无法编译,因为 fn 的参数类型一旦被调用就被固定下来,但希望它能说明我在胡说什么。

main = putStrLn (foo id)

foo :: (* -> *) -> [Char] -- maybe I'm also getting the whole *-thing wrong
foo fn =
    let
        val1 = fn "hey"
        val2 = fn 42
    in
        show (val1, val2)

我想知道它是否可以实现,如果没有像类型类这样的助手,你是否可以做到。

您要找的是 extension called RankNTypes。使用它,您可以将函数的类型写为:

{-# LANGUAGE RankNTypes #-}

foo :: (forall a. a -> a) -> [Char]

在这种情况下,您唯一可以提供的函数是 id,但您也可以使用类型 类 来允许稍微更有趣的多态函数作为参数。考虑这个版本的函数:

bar:: (forall a. Show a => a -> String) -> String
bar fn =
    let
        val1 = fn "hey"
        val2 = fn 42
    in
        val1 <> val2

* 不是允许使用任何类型的通配符。所以,你的用法是错误的。

要键入您的函数,我们需要指定 fn 的类型。那必须是一个多态函数 returning 一些可以 Showed 的值。

一个可能的解决方案是:

{-# LANGUAGE ScopedTypeVariables, RankNTypes #-}

foo :: forall b. Show b => (forall a. a -> b) -> [Char]
foo fn = let
   val1 = fn "hey"
   val2 = fn 42
   in show (val1, val2)

这要求 fn 接受任何类型 a 和 return 固定类型 b class Show

正如所写,这不是很有用,因为 fn 无法使用它的参数,因为它是泛型类型 a.

也许更有用的变体是 a 属于某种类型 class c,这样至少可以使用 fn 的参数至 c.

foo :: forall b c. (Show b, c String, c Int) 
    => (forall a. c a => a -> b) -> [Char]
foo fn = let
   val1 = fn "hey"
   val2 = fn (42 :: Int)
   in show (val1, val2)