首页 文章

Haskell函数的类型(num - > num) - > num

提问于
浏览
0

我正在努力练习R. Bird的函数式编程书,它要求一个函数的例子(num - > num) - > num

我能想出的最好的是多态类型

func1 f = f 3
:t func1
func1 :: Num t1 => (t1 -> t2) -> t2

我遇到的问题是我无法指定f的返回类型,因此类型仍为(num - > t2) - > t2 .

我强制返回f类型的尝试如下:

square x = x * x
:t func1 square
func1 square :: Num t2 => t2 -> t2

因为当然如果我试图找到func1∘square的类型,它只会是num - > num

2 回答

  • 0

    func1 f = let x = f x in x 这是一个部分功能,它在技术上具有您想要的类型,您应该知道它们是什么以及它们如何在haskell中工作 .

  • 3

    如果足以提供可以分配该类型的函数,那么您的已经足够了 . 也就是说,以下类型检查就好了:

    func1 :: Num a => (a -> a) -> a
    func1 f = f 3
    

    另一方面,如果你想要一个推断出具有该类型的函数,那么你需要做一些技巧 . 我们在这里要做的是指定 f 3 的结果和我们输入的 3 具有相同的类型 . 强制两个术语具有相同类型的标准方法是使用 asTypeOf ,这是通过以下方式实现的:

    asTypeOf :: a -> a -> a
    asTypeOf x _ = x
    

    所以让我们试试:

    > :t \f -> f 3 `asTypeOf` 3
    (Num a, Num t) => (t -> a) -> a
    

    不幸的是,这不起作用,因为 f 3 中的 3 和独立的 3 被推断为使用了可能不同的 Num 实例 . 尽管如此,它比 \f -> f 3 更接近了 - 请注意我们之前没有输出的新 Num a 约束 . 一个明显的下一个想法是 let -将变量绑定到 3 并将该变量重用为 fasTypeOf 的参数;当然GHC会得到 f 的论点和结果具有相同类型的图片,对吧?

    > :t \f -> let x = 3 in f x `asTypeOf` x
    (Num a, Num t) => (t -> a) -> a
    

    讨厌鬼 . 事实证明 let 做了所谓的"let generalization"; x 将与 3 一样多态,并且可以专门用于不同使用站点的不同类型 . 通常这是一个很好的功能,但因为我们正在做一个不自然的运动,我们需要做一些不自然的事情......

    好的,下一个想法:一些lambda calculi不包含 let ,当你需要一个时,而不是写 let a = b in c ,你写 (\a -> c) b . 这对我们来说特别有趣,因为Haskell使用了一种特殊限制的多态,这意味着在 c 中, a 的类型是单态的 . 所以:

    > :t \f -> (\x -> f x `asTypeOf` x) 3
    Num a => (a -> a) -> a
    

    现在你抱怨 asTypeOf 在作弊,因为它使用的类型声明与推断类型不匹配,我们可以在开始时从 func1 :: Num a => (a -> a) -> a; func1 f = f 3 停止!)好的,没问题:还有另一种标准方法可以强迫要统一的两个表达式的类型,即将它们放在一起列表中 . 所以:

    > :t \f -> (\x -> head [f x, x]) 3
    Num a => (a -> a) -> a
    

    Phew,现在我们终于可以在原则上从头开始构建所需的所有工具,无需任何类型声明即可获得正确类型的术语 .

相关问题