[HN Gopher] Show HN: Leporello.js - interactive functional progr...
       ___________________________________________________________________
        
       Show HN: Leporello.js - interactive functional programming IDE for
       JavaScript
        
       Hi! Leporello.js is an interactive functional programming
       environment designed for pure functional subset of JavaScript. It
       executes code instantly as you type and displays results next to
       it. Leporello.js also features an omnipresent debugger. Just
       position your cursor on any line or select any expression, and
       immediately see its value. Leporello.js visualizes a dynamic call
       tree of your program. Thanks to the data immutability in functional
       programming, it allows you to navigate the call tree both forward
       and backward, offering a time-travel-like experience. Leporello.js
       offers the ability to develop HTML5 applications interactively,
       enabling you to update your code without losing the application's
       state.  It records an IO trace of your program, which is then
       transparently replayed during subsequent program executions. This
       allows you to instantly reexecute your code after making small
       tweaks, thereby tightening your feedback loop.  Furthermore,
       Leporello.js can serve as an interactive notebook. You have the
       flexibility to utilize any JavaScript libraries to visualize your
       data directly within your code.  For a more detailed walkthrough,
       please watch the product video. Currently, Leporello.js is
       available as a free online application that you can try right in
       your browser. My goal is to build the Leporello.js standalone
       Electron app and a VSCode plugin, both with TypeScript support.
       Additionally, I plan to add Node.js support (currently,
       Leporello.js is only for HTML5 apps). In the VSCode plugin,
       Leporello.js will sit on top of the built-in TypeScript/JavaScript
       mode, utilizing its code analysis information to enhance the
       default VSCode experience with unique Leporello.js features.  I am
       building Leporello.js as a single independent developer.
       Leporello.js is funded solely by donations. Support me on Github
       Sponsors [0] and be the first to gain access to the Leporello.js
       Visual Studio Code plugin with TypeScript support.  I'll be
       delighted to answer any questions you may have.  [0]
       https://github.com/sponsors/leporello-js
        
       Author : dmitry-vsl
       Score  : 69 points
       Date   : 2023-10-03 12:36 UTC (10 hours ago)
        
 (HTM) web link (leporello.tech)
 (TXT) w3m dump (leporello.tech)
        
       | thriftwy wrote:
       | Zdravstvuite, Dmitrii Evgen'evich!
        
       | skrebbel wrote:
       | Wow this looks pretty spectacular. At first I was annoyed that I
       | had to play a video to get it, but I then had to admit that
       | there's no real way to convey this so well with text.
       | 
       | That VS Code plugin sounds particularly amazing. How do you plan
       | to scope things? Notably how would I avoid it accidentally re-
       | running side effects?
        
         | dmitry-vsl wrote:
         | I plan to blog about Leporello.js internals, but now I will try
         | to give you a short answer.
         | 
         | When navigating a call tree, Leporello.js evaluates your
         | functions with tracing enabled, collecting execution
         | information and materializing parts of the call tree in memory.
         | This evaluation is lazy, but if a function invokes an IO
         | operation, the corresponding call tree node is saved eagerly to
         | ensure the function is called only once, avoiding duplicate IO
         | operations.
         | 
         | Handling state mutations is more complex. Leporello.js doesn't
         | inherently know if a function, possibly from a third-party
         | library, will mutate its arguments. Therefore, when using such
         | functions, there's a risk of displaying incorrect data when you
         | navigate and debug your code.
         | 
         | Ideally, a language would color functions based on their
         | purity, allowing smart IDEs to deep clone arguments before
         | invoking impure functions, enabling time-travel debugging.
         | Maybe I will add comment pragmas to Leporello.js. They would
         | allow to have state-mutating functions as first-class citizens
         | in Leporello.js. Syntactically, they can be just ordinary
         | comments:                 // leporello: mutation       function
         | sort(arr) {          arr.sort() // in javascript, sort mutates
         | array in-place       }
         | 
         | Currently, this responsibility falls on the programmer. If you
         | use argument-mutating functions, consider wrapping them in a
         | pure functional interface. The viable approach is structuring
         | your program with a 'functional core, imperative shell'
         | architecture. This approach, as seen in Leporello.js itself,
         | involves a main codebase that is pure functional, operating on
         | a single immutable data structure describing Leporello.js's
         | state, while the 'shell' part invokes pure functions and
         | applies effects.
         | 
         | The notable example of such architecture is Redux. Redux
         | architecture fits perfectly for apps build with Leporello.js,
         | as you can see in TODO app example
         | https://app.leporello.tech/?example=todos-preact
        
       | ericol wrote:
       | This looks seriously awesome. Favorited it for later.
       | 
       | As a side note who / what narrates the video? ;)
        
         | dmitry-vsl wrote:
         | It is an AI voice generator https://genny.lovo.ai/
        
         | aragonite wrote:
         | it's the same AI girl voice you hear in like 30% of tiktok
         | videos.
         | 
         | And she pronounced 'console' wrong. The noun should be
         | pronounced /'ka:n.soUl/, not /k@n'soUl/.
        
       | wredue wrote:
       | The functional web has been complete and utter dogshit. Can we
       | just navigate away from this failure of an experiment already?
        
       | p2hari wrote:
       | Really awesome , would love to see typescript support.
        
       | artisin wrote:
       | I dig the core concept, particularly since I've been searching
       | for a more efficient alternative to opening a blank DevTools
       | window for executing various helper scripts. With that in mind,
       | what about introducing a "Loose Mode" option of sorts, akin to a
       | basic js interpreter? Granted, most of the tool's interactive
       | functionalities probably wouldn't work in this simplified mode,
       | but it would, in turn, expand the tool's overall versatility.
       | Enabling you to use previously written scripts and/or experiment
       | with code (such as copying an example snippet from the README)
       | without having to first adapt it to a functional paradigm.
        
         | dmitry-vsl wrote:
         | I agree that enforcing strict purity in Leporello.js might
         | limit its adoption among developers who prefer a more flexible
         | approach. However, this initial focus on a pure functional
         | subset allowed me to concentrate on the core idea - reimagining
         | developer tools for functional programming from the ground up.
         | 
         | Exploring the development of a two-mode debugger that can
         | seamlessly switch between traditional imperative debugging and
         | Leporello.js-style debugging for pure functions in modern
         | multiparadigm languages is indeed an intriguing research
         | avenue.
        
           | TerrifiedMouse wrote:
           | Hope you don't mind answering a few questions of mine.
           | 
           | What's the functional subset of JS? Any literature on this
           | subset? I don't really know JS apart from hacking together a
           | few scripts for fun.
           | 
           | If this is purely functional, does this mean we will need to
           | use monads for IO like in Haskell?
        
             | dmitry-vsl wrote:
             | Leporello.js follows a pragmatic functional approach. You
             | can use IO functions and throw exceptions as you typically
             | would, without the need for an IO monad or an Option monad.
             | However, there is one critical limitation - you cannot
             | mutate your data structures. Mutations are not allowed
             | because they would make time-travel debugging impossible.
             | For instance, the following code is forbidden:
             | const point = {x: 1, y: 2}       point.x = 2
             | 
             | And instead you should use this:                 const
             | point = {x: 1, y: 2}       const another_point = {...point,
             | x : 2}
             | 
             | In Leporello.js, it's vital to avoid mutating data
             | structures; instead, you create new ones. You can watch
             | Rich Hickey's insightful talk [0], where he discusses the
             | advantages of immutability in functional programming.
             | 
             | In many ways, Leporello.js bears a resemblance to Clojure.
             | Clojure served as a source of inspiration for Leporello.js,
             | to the extent that I even contemplated building
             | Leporello.js for Clojure first.
             | 
             | [0] https://www.youtube.com/watch?v=-6BsiVyC1kM
        
               | aragonite wrote:
               | The comma operator also seems forbidden. I guess there's
               | never a need to use it in purely function code, but the
               | code can still qualify as pure even allowing its use?
               | 
               | fib(6), fib(7) // _scratch_ :9:6 - unexpected token
        
               | dmitry-vsl wrote:
               | Currently, Leporello.js relies on my custom JavaScript
               | parser, which, while functional, is not yet complete and
               | exhibits some quirks. My plan is to replace it with a
               | TypeScript parser, thereby providing full support for
               | both JavaScript and TypeScript within Leporello.js.
               | Additionally, I'm going to develop a VSCode extension,
               | which will offer you all the features available in ts-
               | server.
        
               | aragonite wrote:
               | Sounds exciting. Looking forward to trying out the
               | extension!
        
       | metadat wrote:
       | OP: Bug report- With Brave on Android the "try it" demo
       | constantly zooms way, way in, making this unusable on mobile.
        
       | ithkuil wrote:
       | Something like this but for jsonnet could definitely help people
       | grokking how jsonnet works.
       | 
       | I do believe that jsonnet (despite all it's real problems) is an
       | underestimated jewel mostly because of the embryonic level of its
       | tooling. An ide/debugger like this could help.
       | 
       | EDIT: some tangentially related work:
       | https://github.com/kubecfg/ursonnet
        
         | dmitry-vsl wrote:
         | I don't have any experience with Jsonnet, but from what I can
         | gather, it appears to be a Turing-complete functional
         | programming language. Leporello.js, on the other hand, is a UX
         | concept that can be applied to any functional programming
         | language, including Jsonnet.
         | 
         | In fact, I believe it's possible to write code in TypeScript
         | that would be very similar to Jsonnet. TypeScript provides the
         | capability to create compiler plugins, which can restrict the
         | allowed language subset, effectively making it more limited and
         | suitable for configuration
        
       | BobJS wrote:
       | Are you using the monaco editor? If so please enable the
       | autoClosingBrackets:
       | 
       | ```js
       | 
       | monaco.editor.create(document.getElementById('container'), {
       | value: 'const myVar = hello',              language:
       | 'javascript',              autoClosingBrackets: 'always'  // <---
       | This
       | 
       | });
       | 
       | ```
       | 
       | When I highlight "hello world" and press ', I want to see "'hello
       | world'" instead of "'"
       | 
       | All that aside, awesome project
        
         | dmitry-vsl wrote:
         | Thank you for the suggestion! I am using the Ace editor. I will
         | consider adding a configuration option, but my main goal is to
         | build a VSCode plugin, so all the configuration will be left to
         | the user.
        
           | meowtimemania wrote:
           | sounds amazing. Your tool is super useful for understanding
           | recursive functions. Only thing I felt that I was missing
           | when using this was a format button to fix the formatting of
           | my code.
        
             | dmitry-vsl wrote:
             | Thank you for your feedback! I believe it has some value in
             | teaching programming in the spirit of "Structure and
             | Interpretation of Computer Programs." There is a JavaScript
             | edition of the SICP book. I believe Leporello.js would be a
             | nice environment for students to solve problems from this
             | book.
        
       | FractalHQ wrote:
       | This looks awesome. Any plans to support Typescript? I can't
       | stomach vanilla JavaScript these days.
       | 
       | Edit: that vscode extension with typescript support actually
       | seems perfect for me!
        
       ___________________________________________________________________
       (page generated 2023-10-03 23:01 UTC)