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



出于纯粹的好奇,我想知道在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)

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

您正在寻找的是一个名为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

*不是允许使用任何类型的通配符。因此,你用that是错误的。

要键入函数,我们需要指定fn的类型。它必须是一个多态函数,返回一些可以被Show编辑的值。

一个可能的解决方案是:

{-# 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,并返回一个固定类型b,它属于Show类。

如前所述,这并不是非常有用,因为fn无法使用它的参数,因为它是泛型a

也许更有用的变体是将a属于某个类型类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)

最新更新