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

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

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

回答

您正在寻找的是一个名为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. 那必须是一个多态函数,返回一些可以被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的 class 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)


以上是具有多种参数类型的多态输入函数的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>