Are there any valid definitions of this lambda statement in Haskell?
up vote
1
down vote
favorite
I have the following definition for a function in Haskell.
> q7 :: forall a. forall b. ((a -> b) -> a) -> a
I am challenged to either create a definition for it, or state why a definition does not exist. Here are my thoughts:
q7
takes in any types for a
and b
. The statement (a -> b) -> a
would be implemented by taking two items and returning the latter. Now, if I go one tier further, I can just return this same "a
" to fulfill ((a -> b) -> a) -> a
. I see an issue in that a
and b
can be any type, so for each instance of a
, could a
be a different type? For example, could it be something like ((Int -> Bool) -> [Char]) -> Int
? I probably murdered that syntax. If anyone has any hints or if anyone can confirm or deny my ideas, I would appreciate it greatly!
haskell typing lambda-calculus
add a comment |
up vote
1
down vote
favorite
I have the following definition for a function in Haskell.
> q7 :: forall a. forall b. ((a -> b) -> a) -> a
I am challenged to either create a definition for it, or state why a definition does not exist. Here are my thoughts:
q7
takes in any types for a
and b
. The statement (a -> b) -> a
would be implemented by taking two items and returning the latter. Now, if I go one tier further, I can just return this same "a
" to fulfill ((a -> b) -> a) -> a
. I see an issue in that a
and b
can be any type, so for each instance of a
, could a
be a different type? For example, could it be something like ((Int -> Bool) -> [Char]) -> Int
? I probably murdered that syntax. If anyone has any hints or if anyone can confirm or deny my ideas, I would appreciate it greatly!
haskell typing lambda-calculus
4
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.
– n.m.
Nov 14 at 17:43
It's the samea
throughout;((int -> bool) -> [Char]) -> int
isn't valid, because you can't unifyint
and[Char]
. Quantification extends as far right as possible.
– chepner
Nov 14 at 18:13
1
But more to the point, @n.m. is saying that(a -> b) -> a
is not the same asa -> b -> a
; the->
operator is right-associative.
– chepner
Nov 14 at 18:20
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have the following definition for a function in Haskell.
> q7 :: forall a. forall b. ((a -> b) -> a) -> a
I am challenged to either create a definition for it, or state why a definition does not exist. Here are my thoughts:
q7
takes in any types for a
and b
. The statement (a -> b) -> a
would be implemented by taking two items and returning the latter. Now, if I go one tier further, I can just return this same "a
" to fulfill ((a -> b) -> a) -> a
. I see an issue in that a
and b
can be any type, so for each instance of a
, could a
be a different type? For example, could it be something like ((Int -> Bool) -> [Char]) -> Int
? I probably murdered that syntax. If anyone has any hints or if anyone can confirm or deny my ideas, I would appreciate it greatly!
haskell typing lambda-calculus
I have the following definition for a function in Haskell.
> q7 :: forall a. forall b. ((a -> b) -> a) -> a
I am challenged to either create a definition for it, or state why a definition does not exist. Here are my thoughts:
q7
takes in any types for a
and b
. The statement (a -> b) -> a
would be implemented by taking two items and returning the latter. Now, if I go one tier further, I can just return this same "a
" to fulfill ((a -> b) -> a) -> a
. I see an issue in that a
and b
can be any type, so for each instance of a
, could a
be a different type? For example, could it be something like ((Int -> Bool) -> [Char]) -> Int
? I probably murdered that syntax. If anyone has any hints or if anyone can confirm or deny my ideas, I would appreciate it greatly!
haskell typing lambda-calculus
haskell typing lambda-calculus
edited Nov 15 at 2:25
duplode
22.8k44581
22.8k44581
asked Nov 14 at 17:34
Adrian Bernat
187
187
4
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.
– n.m.
Nov 14 at 17:43
It's the samea
throughout;((int -> bool) -> [Char]) -> int
isn't valid, because you can't unifyint
and[Char]
. Quantification extends as far right as possible.
– chepner
Nov 14 at 18:13
1
But more to the point, @n.m. is saying that(a -> b) -> a
is not the same asa -> b -> a
; the->
operator is right-associative.
– chepner
Nov 14 at 18:20
add a comment |
4
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.
– n.m.
Nov 14 at 17:43
It's the samea
throughout;((int -> bool) -> [Char]) -> int
isn't valid, because you can't unifyint
and[Char]
. Quantification extends as far right as possible.
– chepner
Nov 14 at 18:13
1
But more to the point, @n.m. is saying that(a -> b) -> a
is not the same asa -> b -> a
; the->
operator is right-associative.
– chepner
Nov 14 at 18:20
4
4
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.– n.m.
Nov 14 at 17:43
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.– n.m.
Nov 14 at 17:43
It's the same
a
throughout; ((int -> bool) -> [Char]) -> int
isn't valid, because you can't unify int
and [Char]
. Quantification extends as far right as possible.– chepner
Nov 14 at 18:13
It's the same
a
throughout; ((int -> bool) -> [Char]) -> int
isn't valid, because you can't unify int
and [Char]
. Quantification extends as far right as possible.– chepner
Nov 14 at 18:13
1
1
But more to the point, @n.m. is saying that
(a -> b) -> a
is not the same as a -> b -> a
; the ->
operator is right-associative.– chepner
Nov 14 at 18:20
But more to the point, @n.m. is saying that
(a -> b) -> a
is not the same as a -> b -> a
; the ->
operator is right-associative.– chepner
Nov 14 at 18:20
add a comment |
3 Answers
3
active
oldest
votes
up vote
5
down vote
accepted
It's impossible, except by using infinite recursion or runtime errors, so to fail to terminate.
We can prove that it is indeed impossible, exploiting some results from theoretical computer science. I don't know if there's an easier way to show that it's indeed impossible.
If there were a way to write a terminating program with that type, by the Curry-Howard correspondence, we would get that the logical formula ((a -> b) -> a) -> a
(here, read ->
as "implies") is a theorem of propositional intuitionistic logic.
Such formula is known as Peirce's Law, and is one of the key examples of a formula which is NOT provable in intuitionistic logic (by constrast, it is a theorem in classical logic).
As a reasonably easy way to prove that Peirce's law is not an intuitionistic theorem, one can run a decision procedure for propositional intuitionistic logic, and observe that it outputs "not a theorem". As such procedure, we could perform a search for a cut-free proof in Gentzen's LJ sequent calculus: in this way we only need to check a finite (and smallish) number of possible proofs, and observe that each attempt fails.
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
add a comment |
up vote
3
down vote
Suppose you have a function
pierce :: ((a -> b) -> a) -> a
Import
data Void
from Data.Void
.
Now we get to play games. We can instantiate a
and b
in the type of pierce
to whatever we like. Let's define
type A p = Either p (p -> Void)
and instantiate with
a ~ A p
b ~ Void
So
pierce :: ((A p -> Void) -> A p) -> A p
Let's write a helper:
noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
where
m :: p -> Void
m = apv . Left
n :: (p -> Void) -> Void
n = apv . Right
Now we can go for the kill:
lem :: Either p (p -> Void)
lem = pierce noNegate
If this function existed, it would be very strange.
lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow
The behavior of this function seems so weird because it violates parametricity, which Haskell functions can't do, but things only get worse for it.
It's possible (but slightly annoying) to encode an arbitrary Turing machine as a Haskell type. And it's possible to design a type representing a proof that a particular Turing machine will halt (basically a type-indexed execution trace). Applying lem
at such a trace type would solve the halting problem.
Thanks to Haskell's laziness, some "impossible" functions turn out to be useful, albeit partial. For example,
fix :: (a -> a) -> a
is formally absurd, since fix id
claims to give you anything you want. pierce
is not such a function. Let's try to write it:
pierce :: ((a -> b) -> a) -> a
pierce f = _
What must go on the right side? The only way to make an a
is by applying f
.
pierce f = f _
We must now supply something of type a -> b
. We don't have one. We don't know what b
is, so we can't pull the usual trick of starting with some b
constructor to gain a beat. Nothing can ever improve our b
. So the very best we can do is
pierce f = f (const undefined)
which doesn't look remotely useful.
add a comment |
up vote
1
down vote
The statement (a -> b) -> a would be implemented by taking two items and returning the latter.
You're confusing this with a -> b -> a
(which can also be written a -> (b -> a)
. This is not the same.
(a -> b) -> a
is a function that takes a single argument and returns a value of type a
. The argument has type a -> b
, which means it is a function that takes a value of type a
and returns a value of type b
. This is not unlike (for example) the filter
function:
filter :: (a -> Bool) -> [a] -> [a]
This takes two arguments, a predicate function of type a -> Bool
and a list of type [a]
, and returns a new filtered [a]
value by passing each list item to the predicate.
I see an issue in that a and b can be any type, so for each instance of a, could a be a different type?
No, if it could it would have a different name. a
can be any type, but once you pick a type for a
, every a
in that type signature stands for that type. The b
is a different letter, so it can be a different type from a
.
So, for your type signature ((a -> b) -> a) -> a
, you would write a function that takes a single argument (another function) and returns an a
. The argument function has type (a -> b) -> a
, which means it takes a function of type a -> b
as an argument and returns an a
.
func :: ((a -> b) -> a) -> a
func f = ...
The argument f
, if called, would return an a
that you could then return from func
:
func :: ((a -> b) -> a) -> a
func f = f x
where x :: a -> b
x = ...
However, to call f
you would need to pass it a function a -> b
, for all types a
and b
. As you don't have such a function available, and there's no way to write such a function in general, I think this is impossible to implement.
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
accepted
It's impossible, except by using infinite recursion or runtime errors, so to fail to terminate.
We can prove that it is indeed impossible, exploiting some results from theoretical computer science. I don't know if there's an easier way to show that it's indeed impossible.
If there were a way to write a terminating program with that type, by the Curry-Howard correspondence, we would get that the logical formula ((a -> b) -> a) -> a
(here, read ->
as "implies") is a theorem of propositional intuitionistic logic.
Such formula is known as Peirce's Law, and is one of the key examples of a formula which is NOT provable in intuitionistic logic (by constrast, it is a theorem in classical logic).
As a reasonably easy way to prove that Peirce's law is not an intuitionistic theorem, one can run a decision procedure for propositional intuitionistic logic, and observe that it outputs "not a theorem". As such procedure, we could perform a search for a cut-free proof in Gentzen's LJ sequent calculus: in this way we only need to check a finite (and smallish) number of possible proofs, and observe that each attempt fails.
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
add a comment |
up vote
5
down vote
accepted
It's impossible, except by using infinite recursion or runtime errors, so to fail to terminate.
We can prove that it is indeed impossible, exploiting some results from theoretical computer science. I don't know if there's an easier way to show that it's indeed impossible.
If there were a way to write a terminating program with that type, by the Curry-Howard correspondence, we would get that the logical formula ((a -> b) -> a) -> a
(here, read ->
as "implies") is a theorem of propositional intuitionistic logic.
Such formula is known as Peirce's Law, and is one of the key examples of a formula which is NOT provable in intuitionistic logic (by constrast, it is a theorem in classical logic).
As a reasonably easy way to prove that Peirce's law is not an intuitionistic theorem, one can run a decision procedure for propositional intuitionistic logic, and observe that it outputs "not a theorem". As such procedure, we could perform a search for a cut-free proof in Gentzen's LJ sequent calculus: in this way we only need to check a finite (and smallish) number of possible proofs, and observe that each attempt fails.
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
add a comment |
up vote
5
down vote
accepted
up vote
5
down vote
accepted
It's impossible, except by using infinite recursion or runtime errors, so to fail to terminate.
We can prove that it is indeed impossible, exploiting some results from theoretical computer science. I don't know if there's an easier way to show that it's indeed impossible.
If there were a way to write a terminating program with that type, by the Curry-Howard correspondence, we would get that the logical formula ((a -> b) -> a) -> a
(here, read ->
as "implies") is a theorem of propositional intuitionistic logic.
Such formula is known as Peirce's Law, and is one of the key examples of a formula which is NOT provable in intuitionistic logic (by constrast, it is a theorem in classical logic).
As a reasonably easy way to prove that Peirce's law is not an intuitionistic theorem, one can run a decision procedure for propositional intuitionistic logic, and observe that it outputs "not a theorem". As such procedure, we could perform a search for a cut-free proof in Gentzen's LJ sequent calculus: in this way we only need to check a finite (and smallish) number of possible proofs, and observe that each attempt fails.
It's impossible, except by using infinite recursion or runtime errors, so to fail to terminate.
We can prove that it is indeed impossible, exploiting some results from theoretical computer science. I don't know if there's an easier way to show that it's indeed impossible.
If there were a way to write a terminating program with that type, by the Curry-Howard correspondence, we would get that the logical formula ((a -> b) -> a) -> a
(here, read ->
as "implies") is a theorem of propositional intuitionistic logic.
Such formula is known as Peirce's Law, and is one of the key examples of a formula which is NOT provable in intuitionistic logic (by constrast, it is a theorem in classical logic).
As a reasonably easy way to prove that Peirce's law is not an intuitionistic theorem, one can run a decision procedure for propositional intuitionistic logic, and observe that it outputs "not a theorem". As such procedure, we could perform a search for a cut-free proof in Gentzen's LJ sequent calculus: in this way we only need to check a finite (and smallish) number of possible proofs, and observe that each attempt fails.
edited Nov 14 at 22:22
answered Nov 14 at 19:39
chi
72.4k280134
72.4k280134
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
add a comment |
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
You can also go for the halting problem. See my answer, which goes through the excluded middle.
– dfeuer
Nov 14 at 23:18
add a comment |
up vote
3
down vote
Suppose you have a function
pierce :: ((a -> b) -> a) -> a
Import
data Void
from Data.Void
.
Now we get to play games. We can instantiate a
and b
in the type of pierce
to whatever we like. Let's define
type A p = Either p (p -> Void)
and instantiate with
a ~ A p
b ~ Void
So
pierce :: ((A p -> Void) -> A p) -> A p
Let's write a helper:
noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
where
m :: p -> Void
m = apv . Left
n :: (p -> Void) -> Void
n = apv . Right
Now we can go for the kill:
lem :: Either p (p -> Void)
lem = pierce noNegate
If this function existed, it would be very strange.
lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow
The behavior of this function seems so weird because it violates parametricity, which Haskell functions can't do, but things only get worse for it.
It's possible (but slightly annoying) to encode an arbitrary Turing machine as a Haskell type. And it's possible to design a type representing a proof that a particular Turing machine will halt (basically a type-indexed execution trace). Applying lem
at such a trace type would solve the halting problem.
Thanks to Haskell's laziness, some "impossible" functions turn out to be useful, albeit partial. For example,
fix :: (a -> a) -> a
is formally absurd, since fix id
claims to give you anything you want. pierce
is not such a function. Let's try to write it:
pierce :: ((a -> b) -> a) -> a
pierce f = _
What must go on the right side? The only way to make an a
is by applying f
.
pierce f = f _
We must now supply something of type a -> b
. We don't have one. We don't know what b
is, so we can't pull the usual trick of starting with some b
constructor to gain a beat. Nothing can ever improve our b
. So the very best we can do is
pierce f = f (const undefined)
which doesn't look remotely useful.
add a comment |
up vote
3
down vote
Suppose you have a function
pierce :: ((a -> b) -> a) -> a
Import
data Void
from Data.Void
.
Now we get to play games. We can instantiate a
and b
in the type of pierce
to whatever we like. Let's define
type A p = Either p (p -> Void)
and instantiate with
a ~ A p
b ~ Void
So
pierce :: ((A p -> Void) -> A p) -> A p
Let's write a helper:
noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
where
m :: p -> Void
m = apv . Left
n :: (p -> Void) -> Void
n = apv . Right
Now we can go for the kill:
lem :: Either p (p -> Void)
lem = pierce noNegate
If this function existed, it would be very strange.
lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow
The behavior of this function seems so weird because it violates parametricity, which Haskell functions can't do, but things only get worse for it.
It's possible (but slightly annoying) to encode an arbitrary Turing machine as a Haskell type. And it's possible to design a type representing a proof that a particular Turing machine will halt (basically a type-indexed execution trace). Applying lem
at such a trace type would solve the halting problem.
Thanks to Haskell's laziness, some "impossible" functions turn out to be useful, albeit partial. For example,
fix :: (a -> a) -> a
is formally absurd, since fix id
claims to give you anything you want. pierce
is not such a function. Let's try to write it:
pierce :: ((a -> b) -> a) -> a
pierce f = _
What must go on the right side? The only way to make an a
is by applying f
.
pierce f = f _
We must now supply something of type a -> b
. We don't have one. We don't know what b
is, so we can't pull the usual trick of starting with some b
constructor to gain a beat. Nothing can ever improve our b
. So the very best we can do is
pierce f = f (const undefined)
which doesn't look remotely useful.
add a comment |
up vote
3
down vote
up vote
3
down vote
Suppose you have a function
pierce :: ((a -> b) -> a) -> a
Import
data Void
from Data.Void
.
Now we get to play games. We can instantiate a
and b
in the type of pierce
to whatever we like. Let's define
type A p = Either p (p -> Void)
and instantiate with
a ~ A p
b ~ Void
So
pierce :: ((A p -> Void) -> A p) -> A p
Let's write a helper:
noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
where
m :: p -> Void
m = apv . Left
n :: (p -> Void) -> Void
n = apv . Right
Now we can go for the kill:
lem :: Either p (p -> Void)
lem = pierce noNegate
If this function existed, it would be very strange.
lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow
The behavior of this function seems so weird because it violates parametricity, which Haskell functions can't do, but things only get worse for it.
It's possible (but slightly annoying) to encode an arbitrary Turing machine as a Haskell type. And it's possible to design a type representing a proof that a particular Turing machine will halt (basically a type-indexed execution trace). Applying lem
at such a trace type would solve the halting problem.
Thanks to Haskell's laziness, some "impossible" functions turn out to be useful, albeit partial. For example,
fix :: (a -> a) -> a
is formally absurd, since fix id
claims to give you anything you want. pierce
is not such a function. Let's try to write it:
pierce :: ((a -> b) -> a) -> a
pierce f = _
What must go on the right side? The only way to make an a
is by applying f
.
pierce f = f _
We must now supply something of type a -> b
. We don't have one. We don't know what b
is, so we can't pull the usual trick of starting with some b
constructor to gain a beat. Nothing can ever improve our b
. So the very best we can do is
pierce f = f (const undefined)
which doesn't look remotely useful.
Suppose you have a function
pierce :: ((a -> b) -> a) -> a
Import
data Void
from Data.Void
.
Now we get to play games. We can instantiate a
and b
in the type of pierce
to whatever we like. Let's define
type A p = Either p (p -> Void)
and instantiate with
a ~ A p
b ~ Void
So
pierce :: ((A p -> Void) -> A p) -> A p
Let's write a helper:
noNegate :: forall p r. (A p -> Void) -> r
noNegate apv = absurd (n m)
where
m :: p -> Void
m = apv . Left
n :: (p -> Void) -> Void
n = apv . Right
Now we can go for the kill:
lem :: Either p (p -> Void)
lem = pierce noNegate
If this function existed, it would be very strange.
lem @Void = Right id
lem @() = Left ()
lem @Int = Left ... -- some integer, somehow
The behavior of this function seems so weird because it violates parametricity, which Haskell functions can't do, but things only get worse for it.
It's possible (but slightly annoying) to encode an arbitrary Turing machine as a Haskell type. And it's possible to design a type representing a proof that a particular Turing machine will halt (basically a type-indexed execution trace). Applying lem
at such a trace type would solve the halting problem.
Thanks to Haskell's laziness, some "impossible" functions turn out to be useful, albeit partial. For example,
fix :: (a -> a) -> a
is formally absurd, since fix id
claims to give you anything you want. pierce
is not such a function. Let's try to write it:
pierce :: ((a -> b) -> a) -> a
pierce f = _
What must go on the right side? The only way to make an a
is by applying f
.
pierce f = f _
We must now supply something of type a -> b
. We don't have one. We don't know what b
is, so we can't pull the usual trick of starting with some b
constructor to gain a beat. Nothing can ever improve our b
. So the very best we can do is
pierce f = f (const undefined)
which doesn't look remotely useful.
edited Nov 15 at 0:35
answered Nov 14 at 22:55
dfeuer
32.1k347126
32.1k347126
add a comment |
add a comment |
up vote
1
down vote
The statement (a -> b) -> a would be implemented by taking two items and returning the latter.
You're confusing this with a -> b -> a
(which can also be written a -> (b -> a)
. This is not the same.
(a -> b) -> a
is a function that takes a single argument and returns a value of type a
. The argument has type a -> b
, which means it is a function that takes a value of type a
and returns a value of type b
. This is not unlike (for example) the filter
function:
filter :: (a -> Bool) -> [a] -> [a]
This takes two arguments, a predicate function of type a -> Bool
and a list of type [a]
, and returns a new filtered [a]
value by passing each list item to the predicate.
I see an issue in that a and b can be any type, so for each instance of a, could a be a different type?
No, if it could it would have a different name. a
can be any type, but once you pick a type for a
, every a
in that type signature stands for that type. The b
is a different letter, so it can be a different type from a
.
So, for your type signature ((a -> b) -> a) -> a
, you would write a function that takes a single argument (another function) and returns an a
. The argument function has type (a -> b) -> a
, which means it takes a function of type a -> b
as an argument and returns an a
.
func :: ((a -> b) -> a) -> a
func f = ...
The argument f
, if called, would return an a
that you could then return from func
:
func :: ((a -> b) -> a) -> a
func f = f x
where x :: a -> b
x = ...
However, to call f
you would need to pass it a function a -> b
, for all types a
and b
. As you don't have such a function available, and there's no way to write such a function in general, I think this is impossible to implement.
add a comment |
up vote
1
down vote
The statement (a -> b) -> a would be implemented by taking two items and returning the latter.
You're confusing this with a -> b -> a
(which can also be written a -> (b -> a)
. This is not the same.
(a -> b) -> a
is a function that takes a single argument and returns a value of type a
. The argument has type a -> b
, which means it is a function that takes a value of type a
and returns a value of type b
. This is not unlike (for example) the filter
function:
filter :: (a -> Bool) -> [a] -> [a]
This takes two arguments, a predicate function of type a -> Bool
and a list of type [a]
, and returns a new filtered [a]
value by passing each list item to the predicate.
I see an issue in that a and b can be any type, so for each instance of a, could a be a different type?
No, if it could it would have a different name. a
can be any type, but once you pick a type for a
, every a
in that type signature stands for that type. The b
is a different letter, so it can be a different type from a
.
So, for your type signature ((a -> b) -> a) -> a
, you would write a function that takes a single argument (another function) and returns an a
. The argument function has type (a -> b) -> a
, which means it takes a function of type a -> b
as an argument and returns an a
.
func :: ((a -> b) -> a) -> a
func f = ...
The argument f
, if called, would return an a
that you could then return from func
:
func :: ((a -> b) -> a) -> a
func f = f x
where x :: a -> b
x = ...
However, to call f
you would need to pass it a function a -> b
, for all types a
and b
. As you don't have such a function available, and there's no way to write such a function in general, I think this is impossible to implement.
add a comment |
up vote
1
down vote
up vote
1
down vote
The statement (a -> b) -> a would be implemented by taking two items and returning the latter.
You're confusing this with a -> b -> a
(which can also be written a -> (b -> a)
. This is not the same.
(a -> b) -> a
is a function that takes a single argument and returns a value of type a
. The argument has type a -> b
, which means it is a function that takes a value of type a
and returns a value of type b
. This is not unlike (for example) the filter
function:
filter :: (a -> Bool) -> [a] -> [a]
This takes two arguments, a predicate function of type a -> Bool
and a list of type [a]
, and returns a new filtered [a]
value by passing each list item to the predicate.
I see an issue in that a and b can be any type, so for each instance of a, could a be a different type?
No, if it could it would have a different name. a
can be any type, but once you pick a type for a
, every a
in that type signature stands for that type. The b
is a different letter, so it can be a different type from a
.
So, for your type signature ((a -> b) -> a) -> a
, you would write a function that takes a single argument (another function) and returns an a
. The argument function has type (a -> b) -> a
, which means it takes a function of type a -> b
as an argument and returns an a
.
func :: ((a -> b) -> a) -> a
func f = ...
The argument f
, if called, would return an a
that you could then return from func
:
func :: ((a -> b) -> a) -> a
func f = f x
where x :: a -> b
x = ...
However, to call f
you would need to pass it a function a -> b
, for all types a
and b
. As you don't have such a function available, and there's no way to write such a function in general, I think this is impossible to implement.
The statement (a -> b) -> a would be implemented by taking two items and returning the latter.
You're confusing this with a -> b -> a
(which can also be written a -> (b -> a)
. This is not the same.
(a -> b) -> a
is a function that takes a single argument and returns a value of type a
. The argument has type a -> b
, which means it is a function that takes a value of type a
and returns a value of type b
. This is not unlike (for example) the filter
function:
filter :: (a -> Bool) -> [a] -> [a]
This takes two arguments, a predicate function of type a -> Bool
and a list of type [a]
, and returns a new filtered [a]
value by passing each list item to the predicate.
I see an issue in that a and b can be any type, so for each instance of a, could a be a different type?
No, if it could it would have a different name. a
can be any type, but once you pick a type for a
, every a
in that type signature stands for that type. The b
is a different letter, so it can be a different type from a
.
So, for your type signature ((a -> b) -> a) -> a
, you would write a function that takes a single argument (another function) and returns an a
. The argument function has type (a -> b) -> a
, which means it takes a function of type a -> b
as an argument and returns an a
.
func :: ((a -> b) -> a) -> a
func f = ...
The argument f
, if called, would return an a
that you could then return from func
:
func :: ((a -> b) -> a) -> a
func f = f x
where x :: a -> b
x = ...
However, to call f
you would need to pass it a function a -> b
, for all types a
and b
. As you don't have such a function available, and there's no way to write such a function in general, I think this is impossible to implement.
edited Nov 14 at 19:56
answered Nov 14 at 19:44
DarthFennec
1,271711
1,271711
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53305859%2fare-there-any-valid-definitions-of-this-lambda-statement-in-haskell%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
4
(a -> b) -> a
is a type of a function that takes a single argument (which is itself a function). There is no second item to return.– n.m.
Nov 14 at 17:43
It's the same
a
throughout;((int -> bool) -> [Char]) -> int
isn't valid, because you can't unifyint
and[Char]
. Quantification extends as far right as possible.– chepner
Nov 14 at 18:13
1
But more to the point, @n.m. is saying that
(a -> b) -> a
is not the same asa -> b -> a
; the->
operator is right-associative.– chepner
Nov 14 at 18:20