JSCAD User Group

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups

    Aug 11, 2018

    Archives (Google+)
    1
    1
    1405
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • z3dev
      z3dev last edited by

      Jared Deckard
      I noticed function currying mentioned in the V2 brain storming doc. I am not using the CSG prototype methods since they are deprecated and I am starting to feel the awkwardness of nested operations. It would be nice if operations could take an option set without an object so that operations can be reused and manipulated as lists.

      move = translate([1, 2, 3])
      move(shape1)
      move(shape2)
      
      shape = do(
          translate([1, 2, 3]),
          rotate([0, 0, 45]),
          scale([3, 2, 1]),
          shape
      )
      

      I'm not sure if this is quite what you had in mind for currying, but I think it gets very close to the conciseness of OpenSCAD. I though I would gather some feedback and see if there is any existing progress before I start hacking on a prototype.
      4 comments
      4
      2 plus ones
      2
      no shares
      Shared publicly•View activity

      Jared Deckard
      +1
      Thanks for your insight. If you need any help fleshing the V2 roadmap out into issues or have some prerequisite issues that would be suitable for a "help wanted" tag, I am happy to help.
      
      Without a clear direction for working towards this feature in V2, I will probably implement this as a wrapper around V1 using lodash's curry and a custom pipeline function.
      

      Jared Deckard
      +1
      I have a prototype working:

      Plugin: https://github.com/deckar01/csg-curry/blob/master/index.js

      JSCAD integration: https://github.com/jscad/OpenJSCAD.org/compare/master...deckar01:csg-curry

      Lessons learned:

      • The spread (...) argument breaks lodash's curry implementation
      • Allowing a variable number of arguments via the "arguments" keyword breaks lodash's curry implementation
      • Some operations only accept one object
      • Some operations require an array instead of spread args
      • All the operations that accept spread args accept an array

      Hacks:

      • A custom curry function that ignores Function.length and waits to "close" the curry until it is called with no arguments
      • Injecting curried copies of all csg functions with a "$" prefix
      • Injecting a "$pipeline" function that normalizes multiple objects as a list, then applies curried functions like a stack

      Logo example:

      function main () {
        return $pipeline(
          $scale(10),
          $translate([0, 0, 1.5]),
          $union,
          difference(
            cube({size: 3, center: true}),
            sphere({r: 2, center: true})
          ),
          intersection(
            sphere({r: 1.3, center: true}),
            cube({size: 2.1, center: true})
          )
        )
      }
      

      Proposal:

      • Replace use of the "arguments" keyword with a required "options" dictionary argument
      • Replace spread arguments with a required object/array argument
      • Allow all operations to accept an array of objects
      • Curry the API with lodash/curry
      • Expose a "pipeline" function via the API

      Jared Deckard
      After iterating on the pipeline function a little bit, I no longer think currying is necessary to make a useful pipeline. Currying is elegant and familiar, but orthogonal to the goal of stacking operations without nesting.

      const pipeline = (...ops) => ops.reverse().reduce(
        (args, x) => x && x.call ? [x(...args)] : [x, ...args], []
      )
      
      function main () {
        return pipeline(
          scale, 10,
          translate, [0, 0, 1.5],
          union,
          difference(
            cube({size: 3, center: true}),
            sphere({r: 2, center: true})
          ),
          intersection(
            sphere({r: 1.3, center: true}),
            cube({size: 2.1, center: true})
          )
        )
      }
      

      Would you be interested in a PR that adds this functionality to the API in the master branch? No API change or new dependencies, just a 3 line pipeline utility. I am personally fine with copying this between my script since it is so compact, but I think it could really help clean up the complicated nesting most users will inevitably run into. I was constantly having to break operation chains off into variables at awkward points that were hard to name.

      Jeff Gay
      Jared, can you post the last comment to the issue, #114? We don’t want to loose your thoughts. And we can discuss the possibility of adding this to V2.

      1 Reply Last reply Reply Quote 0
      • First post
        Last post
      Powered by NodeBB | Contributors