How should you type annotate mutually recursive functions in letrec in Typed Racket?
If I understand it correctly this is the correct way to annotate functions defined in a letrec
in Typed Racket:
#lang typed/racket
(letrec ((is-even? (lambda ((n : Nonnegative-Integer))
: Boolean
(or (zero? n)
(is-odd? (sub1 n)))))
(is-odd? (lambda ((n : Nonnegative-Integer))
: Boolean
(and (not (zero? n))
(is-even? (sub1 n))))))
(is-odd? 11))
However this gives the error message:
Type Checker: insufficient type information to typecheck. please add more
type annotations in: is-odd?
A workaround is this:
(local ((: is-even? : Nonnegative-Integer -> Boolean)
(define (is-even? n)
(or (zero? n)
(is-odd? (sub1 n))))
(: is-odd? : Nonnegative-Integer -> Boolean)
(define (is-odd? n)
(and (not (zero? n))
(is-even? (sub1 n)))))
(is-odd? 11))
Also forms of the legacy notation work such as this question but I would expect to be able to annotate letrec
using current notation too.
typed-racket
add a comment |
If I understand it correctly this is the correct way to annotate functions defined in a letrec
in Typed Racket:
#lang typed/racket
(letrec ((is-even? (lambda ((n : Nonnegative-Integer))
: Boolean
(or (zero? n)
(is-odd? (sub1 n)))))
(is-odd? (lambda ((n : Nonnegative-Integer))
: Boolean
(and (not (zero? n))
(is-even? (sub1 n))))))
(is-odd? 11))
However this gives the error message:
Type Checker: insufficient type information to typecheck. please add more
type annotations in: is-odd?
A workaround is this:
(local ((: is-even? : Nonnegative-Integer -> Boolean)
(define (is-even? n)
(or (zero? n)
(is-odd? (sub1 n))))
(: is-odd? : Nonnegative-Integer -> Boolean)
(define (is-odd? n)
(and (not (zero? n))
(is-even? (sub1 n)))))
(is-odd? 11))
Also forms of the legacy notation work such as this question but I would expect to be able to annotate letrec
using current notation too.
typed-racket
add a comment |
If I understand it correctly this is the correct way to annotate functions defined in a letrec
in Typed Racket:
#lang typed/racket
(letrec ((is-even? (lambda ((n : Nonnegative-Integer))
: Boolean
(or (zero? n)
(is-odd? (sub1 n)))))
(is-odd? (lambda ((n : Nonnegative-Integer))
: Boolean
(and (not (zero? n))
(is-even? (sub1 n))))))
(is-odd? 11))
However this gives the error message:
Type Checker: insufficient type information to typecheck. please add more
type annotations in: is-odd?
A workaround is this:
(local ((: is-even? : Nonnegative-Integer -> Boolean)
(define (is-even? n)
(or (zero? n)
(is-odd? (sub1 n))))
(: is-odd? : Nonnegative-Integer -> Boolean)
(define (is-odd? n)
(and (not (zero? n))
(is-even? (sub1 n)))))
(is-odd? 11))
Also forms of the legacy notation work such as this question but I would expect to be able to annotate letrec
using current notation too.
typed-racket
If I understand it correctly this is the correct way to annotate functions defined in a letrec
in Typed Racket:
#lang typed/racket
(letrec ((is-even? (lambda ((n : Nonnegative-Integer))
: Boolean
(or (zero? n)
(is-odd? (sub1 n)))))
(is-odd? (lambda ((n : Nonnegative-Integer))
: Boolean
(and (not (zero? n))
(is-even? (sub1 n))))))
(is-odd? 11))
However this gives the error message:
Type Checker: insufficient type information to typecheck. please add more
type annotations in: is-odd?
A workaround is this:
(local ((: is-even? : Nonnegative-Integer -> Boolean)
(define (is-even? n)
(or (zero? n)
(is-odd? (sub1 n))))
(: is-odd? : Nonnegative-Integer -> Boolean)
(define (is-odd? n)
(and (not (zero? n))
(is-even? (sub1 n)))))
(is-odd? 11))
Also forms of the legacy notation work such as this question but I would expect to be able to annotate letrec
using current notation too.
typed-racket
typed-racket
edited Nov 14 '18 at 18:09
user3414663
asked Nov 14 '18 at 16:47
user3414663user3414663
12117
12117
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You can put type annotations after the function names in the letrec
, like this:
(letrec ([f1 : type1 expr1]
[f2 : type2 expr2])
body)
For your example, that looks like:
(letrec ([is-even? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))
Why does this work, but putting type annotations inside the lambda
doesn't?
It's because making sure each lambda
typechecks relies on the types of is-odd?
and is-even?
respectively. However, if you don't annotate the function-names directly, it can only try to infer those types by typechecking the lambdas.
Annotating the function-names directly means that it doesn't even have to look at the lambdas before it knows what types is-even?
and is-odd?
must have.
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, theletrec
form adds bothis-even? : (-> Nonnegative-Integer Boolean)
andis-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.
– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then theletrec
has to start typechecking the lambdas in an environment where the types are unknown. Theis-even?
lambda gets the information about the type ofis-even?
because of its own type annotations. However theis-odd?
hasn't been typechecked yet. It continues typechecking theis-even?
lambda without going down to look at the type annotations onis-odd?
. It doesn't do "both at once".
– Alex Knauth
Dec 28 '18 at 14:39
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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%2f53305087%2fhow-should-you-type-annotate-mutually-recursive-functions-in-letrec-in-typed-rac%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can put type annotations after the function names in the letrec
, like this:
(letrec ([f1 : type1 expr1]
[f2 : type2 expr2])
body)
For your example, that looks like:
(letrec ([is-even? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))
Why does this work, but putting type annotations inside the lambda
doesn't?
It's because making sure each lambda
typechecks relies on the types of is-odd?
and is-even?
respectively. However, if you don't annotate the function-names directly, it can only try to infer those types by typechecking the lambdas.
Annotating the function-names directly means that it doesn't even have to look at the lambdas before it knows what types is-even?
and is-odd?
must have.
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, theletrec
form adds bothis-even? : (-> Nonnegative-Integer Boolean)
andis-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.
– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then theletrec
has to start typechecking the lambdas in an environment where the types are unknown. Theis-even?
lambda gets the information about the type ofis-even?
because of its own type annotations. However theis-odd?
hasn't been typechecked yet. It continues typechecking theis-even?
lambda without going down to look at the type annotations onis-odd?
. It doesn't do "both at once".
– Alex Knauth
Dec 28 '18 at 14:39
add a comment |
You can put type annotations after the function names in the letrec
, like this:
(letrec ([f1 : type1 expr1]
[f2 : type2 expr2])
body)
For your example, that looks like:
(letrec ([is-even? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))
Why does this work, but putting type annotations inside the lambda
doesn't?
It's because making sure each lambda
typechecks relies on the types of is-odd?
and is-even?
respectively. However, if you don't annotate the function-names directly, it can only try to infer those types by typechecking the lambdas.
Annotating the function-names directly means that it doesn't even have to look at the lambdas before it knows what types is-even?
and is-odd?
must have.
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, theletrec
form adds bothis-even? : (-> Nonnegative-Integer Boolean)
andis-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.
– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then theletrec
has to start typechecking the lambdas in an environment where the types are unknown. Theis-even?
lambda gets the information about the type ofis-even?
because of its own type annotations. However theis-odd?
hasn't been typechecked yet. It continues typechecking theis-even?
lambda without going down to look at the type annotations onis-odd?
. It doesn't do "both at once".
– Alex Knauth
Dec 28 '18 at 14:39
add a comment |
You can put type annotations after the function names in the letrec
, like this:
(letrec ([f1 : type1 expr1]
[f2 : type2 expr2])
body)
For your example, that looks like:
(letrec ([is-even? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))
Why does this work, but putting type annotations inside the lambda
doesn't?
It's because making sure each lambda
typechecks relies on the types of is-odd?
and is-even?
respectively. However, if you don't annotate the function-names directly, it can only try to infer those types by typechecking the lambdas.
Annotating the function-names directly means that it doesn't even have to look at the lambdas before it knows what types is-even?
and is-odd?
must have.
You can put type annotations after the function names in the letrec
, like this:
(letrec ([f1 : type1 expr1]
[f2 : type2 expr2])
body)
For your example, that looks like:
(letrec ([is-even? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(or (zero? n)
(is-odd? (sub1 n))))]
[is-odd? : (-> Nonnegative-Integer Boolean)
(lambda (n)
(and (not (zero? n))
(is-even? (sub1 n))))])
(is-odd? 11))
Why does this work, but putting type annotations inside the lambda
doesn't?
It's because making sure each lambda
typechecks relies on the types of is-odd?
and is-even?
respectively. However, if you don't annotate the function-names directly, it can only try to infer those types by typechecking the lambdas.
Annotating the function-names directly means that it doesn't even have to look at the lambdas before it knows what types is-even?
and is-odd?
must have.
answered Dec 24 '18 at 17:01
Alex KnauthAlex Knauth
5,0321822
5,0321822
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, theletrec
form adds bothis-even? : (-> Nonnegative-Integer Boolean)
andis-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.
– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then theletrec
has to start typechecking the lambdas in an environment where the types are unknown. Theis-even?
lambda gets the information about the type ofis-even?
because of its own type annotations. However theis-odd?
hasn't been typechecked yet. It continues typechecking theis-even?
lambda without going down to look at the type annotations onis-odd?
. It doesn't do "both at once".
– Alex Knauth
Dec 28 '18 at 14:39
add a comment |
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, theletrec
form adds bothis-even? : (-> Nonnegative-Integer Boolean)
andis-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.
– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then theletrec
has to start typechecking the lambdas in an environment where the types are unknown. Theis-even?
lambda gets the information about the type ofis-even?
because of its own type annotations. However theis-odd?
hasn't been typechecked yet. It continues typechecking theis-even?
lambda without going down to look at the type annotations onis-odd?
. It doesn't do "both at once".
– Alex Knauth
Dec 28 '18 at 14:39
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
Your code works but it contains no more information about the types of the two functions than my version does so I don't see how your explanation holds up.
– user3414663
Dec 27 '18 at 14:05
The difference is the order of typechecking vs. type-environment. In my code, the
letrec
form adds both is-even? : (-> Nonnegative-Integer Boolean)
and is-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.– Alex Knauth
Dec 28 '18 at 14:39
The difference is the order of typechecking vs. type-environment. In my code, the
letrec
form adds both is-even? : (-> Nonnegative-Integer Boolean)
and is-odd? : (-> Nonnegative-Integer Boolean)
to the environment before it even looks at the lambdas.– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then the
letrec
has to start typechecking the lambdas in an environment where the types are unknown. The is-even?
lambda gets the information about the type of is-even?
because of its own type annotations. However the is-odd?
hasn't been typechecked yet. It continues typechecking the is-even?
lambda without going down to look at the type annotations on is-odd?
. It doesn't do "both at once".– Alex Knauth
Dec 28 '18 at 14:39
However, if the same amount of information is pushed into the lambdas, then the
letrec
has to start typechecking the lambdas in an environment where the types are unknown. The is-even?
lambda gets the information about the type of is-even?
because of its own type annotations. However the is-odd?
hasn't been typechecked yet. It continues typechecking the is-even?
lambda without going down to look at the type annotations on is-odd?
. It doesn't do "both at once".– Alex Knauth
Dec 28 '18 at 14:39
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.
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%2f53305087%2fhow-should-you-type-annotate-mutually-recursive-functions-in-letrec-in-typed-rac%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