How should you type annotate mutually recursive functions in letrec in Typed Racket?










1















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.










share|improve this question




























    1















    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.










    share|improve this question


























      1












      1








      1








      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.










      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 14 '18 at 18:09







      user3414663

















      asked Nov 14 '18 at 16:47









      user3414663user3414663

      12117




      12117






















          1 Answer
          1






          active

          oldest

          votes


















          0














          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.






          share|improve this answer























          • 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











          • 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











          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
          );



          );













          draft saved

          draft discarded


















          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









          0














          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.






          share|improve this answer























          • 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











          • 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
















          0














          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.






          share|improve this answer























          • 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











          • 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














          0












          0








          0







          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.






          share|improve this answer













          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.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          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, 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


















          • 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











          • 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

















          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




















          draft saved

          draft discarded
















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Use pre created SQLite database for Android project in kotlin

          Darth Vader #20

          Ondo