简体   繁体   English

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

[英]Haskell function with type (num -> num) -> num

I am struggling with an exercise in R. Bird's functional programming book that asks for an example of a function with type (num -> num) -> num 我在R.Bird的函数式编程书中的一个练习中苦苦挣扎,该书要求提供类型为(num-> num)-> num的函数的示例

The best I can come up with is a polymorphic type 我能想到的最好的是多态类型

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

The problem I am having is that I can't specify the return type of f, so the type remains (num -> t2) -> t2. 我遇到的问题是我无法指定f的返回类型,因此该类型仍为(num-> t2)-> t2。

My attempt to force the return type of f is as follows: 我试图强制返回f的类型如下:

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

Because of course if I try to find the type of func1 ∘ square it will just be num -> num 当然,如果我尝试查找func1∘square的类型,它将只是num-> num

If it is enough to give a function which can be assigned that type , then yours is already enough. 如果足以提供可以分配该类型的功能 ,那么您的功能就足够了。 That is, the following type-checks just fine: 也就是说,以下类型检查就可以了:

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

If, on the other hand, you want a function which is inferred to have that type , then you need to do some trickery. 另一方面,如果您想要一个推断为具有该类型的函数,则需要进行一些技巧。 What we want to do here is to specify that the result of f 3 and the 3 that we fed in have the same type. 我们要在此处指定f 3的结果和我们输入的3的类型相同。 The standard way to force two terms to have the same type is to use asTypeOf , which is implemented this way: 强制两个术语具有相同类型的标准方法是使用asTypeOf ,它是通过以下方式实现的:

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

So let's try: 因此,让我们尝试:

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

Unfortunately for us, this doesn't work, because the 3 in f 3 and the standalone 3 are inferred to be using potentially different instances of Num . 不幸的是对于我们来说,这是行不通的,因为3f 3和独立3被推断为使用的潜在不同实例Num Still, it is a bit closer than \\f -> f 3 was -- note the new Num a constraint on the output that we didn't have before. 不过,它比\\f -> f 3还要近一些-注意新的Num a我们之前没有的输出约束。 An obvious next idea is to let -bind a variable to 3 and reuse that variable as the argument to both f and asTypeOf ; 一个明显的下一个想法是let一个可变-bind至3和重用该变量作为参数既fasTypeOf ; surely then GHC will get the picture that f 's argument and result have the same type, right? 那么GHC肯定会得到f的参数和结果具有相同类型的图片,对吗?

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

Drat. 讨厌鬼。 Turns out that let s do what's called "let generalization"; 事实证明, let进行所谓的“让一般化”。 the x will be just as polymorphic as the 3 was, and can be specialized to different types at different use sites. x将与3一样多态,并且可以在不同的使用地点专门用于不同的类型。 Usually this is a nice feature, but because we're doing an unnatural exercise we need to do unnatural things... 通常这是一个不错的功能,但是由于我们进行的是不自然的运动,因此我们需要做不自然的事情...

Okay, next idea: some lambda calculi do not include a let , and when you need one, instead of writing let a = b in c , you write (\\a -> c) b . 好吧,下一个想法:一些lambda演算不包含let ,并且当您需要一个let a = b in c ,您可以写(\\a -> c) b而不是let a = b in c中写let a = b in c (\\a -> c) b This is especially interesting for us because Haskell uses a specially-restricted kind of polymorphism that means that inside c , the type of a is monomorphic . 这对我们来说是特别有趣,因为Haskell使用特殊限制的多态的,这意味着这里面c的类型, a单态 So: 所以:

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

And now you complain that asTypeOf is cheating, because it uses a type declaration that doesn't match its inferred type, and the whole point of the exercise was to get the right type through inference alone. 现在,您抱怨asTypeOf在作弊,因为它使用的类型声明与其推断的类型不匹配,并且整个练习的重点是仅通过推断获得正确的类型。 (If we were okay with using type declarations that don't match the inferred type, we could have stopped at func1 :: Num a => (a -> a) -> a; func1 f = f 3 from way back at the beginning!) Okay, no problem: there's another standardish way to force the types of two expressions to unify, namely, by putting them in a list together. (如果我们可以使用与推断的类型不匹配的类型声明,则可以在func1 :: Num a => (a -> a) -> a; func1 f = f 3处停下来func1 :: Num a => (a -> a) -> a; func1 f = f 3好的,没问题:还有另一种标准的方法可以强制两个表达式的类型统一,即将它们放在一个列表中。 So: 所以:

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

Phew, now we're finally at a place where we could in principle build, from the ground up, all the tools needed to get a term of the right type without any type declarations. ew,现在我们终于可以在原则上从头开始构建无需任何类型声明即可获取正确类型的术语所需的所有工具。

func1 f = let x = fx in x这是一个分函数,从技术上讲,它具有所需的类型,您应了解它们的含义以及它们在haskell中的工作方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM