Jonkman Microblog
  • Login
Show Navigation
  • Public

    • Public
    • Network
    • Groups
    • Popular
    • People

Conversation

Notices

  1. Tuukka (tuturto@mastodon.social)'s status on Saturday, 03-Feb-2018 23:09:18 EST Tuukka Tuukka

    @m455 current release doesn't have let and you have to use setv instead. Good news is that the next release will have let again. https://engineersjourney.wordpress.com/2017/09/17/sneak-peek-of-possible-future/ has a bit of info about it. PR has been merged and next release should have this.
    #lisp #hy

    In conversation Saturday, 03-Feb-2018 23:09:18 EST from mastodon.social permalink

    Attachments

    1. File without filename could not get a thumbnail source.
      Sneak peek of possible future
      By tuturto from Engineer's Journey

      As you may be aware, let was dropped not too long time ago from Hy. While being very integral and essential part of Lisp, it was just really hard to get working correctly and thus it was removed. However, gilch, one of core developers of Hy, didn’t give up the idea and eventually came up with a proposal how let could be written.

      At the time of writing, this is still a pull request , so nothing hasn’t been merged into master yet and things could still change. But I wanted to write about this as it’s super cool feature and showcases some really neat tricks you can pull of with Hy.

      If we start hy with hy –spy, REPL will output Python code. This lets us to examine what goes under the hood. Lets start with a simple example:

      => (require [hy.contrib.walk [let]])
      => (let [a 1] a)
      :let_1235 = {}
      :let_1235['a'] = 1
      :let_1235['a']
      1
      

      Let lives currently in contrib, so it needs to be required before using. Examining spied output reveals that let is turned into a dictionary with gensymed name to avoid name collisions. After this, every usage of the given variable is through that dictionary.

      Remember how lot of troubles with the original let was due to hidden function that was used to create a new lexical scope? Lets see how this new one handles that?

      => (defn nested [a b]
      ...   (let [c (+ a b)]
      ...     (let [c 5] c)))
      def nested(a, b):
          :let_1240 = {}
          :let_1240['c'] = (a + b)
          :let_1241 = {}
          :let_1241['c'] = 5
          return :let_1241['c']
      

      We have just one function, no extra scopes or anything. Pretty cool, right? Nested lets are turned into new dictionaries and rest of the code is rewritten to use the correct one. This might sound simple, but it’s not. The macro that takes care of this is long and complicated.

      What about if we try to confuse the macro and do something silly?

      => (defn tricky [a b c]
      ...   (let [c (+ a b)] (print c))
      ...   (let [c (* a b)] (print c))
      ... (print c)
      ... c)
      def tricky(a, b, c):
          :let_1239 = {}
          :let_1239['c'] = (a + b)
          print(:let_1239['c'])
          :let_1240 = {}
          :let_1240['c'] = (a * b)
          print(:let_1240['c'])
          print(c)
          return c
      

      Looks good to me. In each case, symbol c is coming from correct dictionary and in the end the original argument is used correctly.

      I’m super happy to see this coming together and can’t wait for the pr to be merged.

  • Help
  • About
  • FAQ
  • TOS
  • Privacy
  • Source
  • Version
  • Contact

Jonkman Microblog is a social network, courtesy of SOBAC Microcomputer Services. It runs on GNU social, version 1.2.0-beta5, available under the GNU Affero General Public License.

Creative Commons Attribution 3.0 All Jonkman Microblog content and data are available under the Creative Commons Attribution 3.0 license.

Switch to desktop site layout.