简体   繁体   中英

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

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.

My attempt to force the return type of f is as follows:

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

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. The standard way to force two terms to have the same type is to use asTypeOf , which is implemented this way:

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 . 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. An obvious next idea is to let -bind a variable to 3 and reuse that variable as the argument to both f and asTypeOf ; surely then GHC will get the picture that f 's argument and result have the same type, right?

> :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"; the x will be just as polymorphic as the 3 was, and can be specialized to different types at different use sites. 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 . 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 . 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. (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. 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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