Question: I think I got the answer(s) I was looking for, but I’ll add a bit of context here in case you have further advice: I am generating a GraphQL schema from an application schema (database schema + some extra info). I am doing this as a sequence of transformations on a “schema” map. So I start with an empty map, then generate some object types, then generate some queries, etc @noisesmith how is it inside the call to g? the result of h is passed as an argument I’ll stop there to avoid spamming this channel with unecessary details
              (keys (:nodes hodl-config)))))
         (map #(gen-for-node hodl-config config %)
So I have code similar to this
(apply comp The reason I was expecting to reach high number of compositions (in the low hundreds) was because some of my transformation steps should be executed for each entity type and I am composing those I wrote each transformation as a function that takes two config maps and extra options, and return a 1-arity function which takes a schema and returns a schema

Asked By
hmaurer
Asked At
2017-09-09 23:25:05

Found 15 possible answers.

User Answered At Possible Answer
tagore 2017-09-09 23:30:36 OK, I've never written a graphql api, so grain of salt, but...
hmaurer 2017-09-09 23:30:40 @noisesmith is argument evaluation lazy in clojure?
noisesmith 2017-09-09 23:30:59 you can see by throwing an exception, one moment, generating an example in my repl
hmaurer 2017-09-09 23:31:19 the fact that it’s a GraphQL schema is irrelevant tbh, I just mentioned it to give context is that what you meant? here the argument seems to be evaluate beforehand
nil
-> foo
abc
boot.user=> (foo (println "abc"))
#'boot.user/foo
boot.user=> (defn foo [x] (println "-> foo")) the essence is, I think, building up a map as a sequence of parametarized transformations
tagore 2017-09-09 23:34:06 I've never felt the need to compose functions that deeply, nor have I seen anyone else need to.
hmaurer 2017-09-09 23:34:09 or are they evaluated “just as you get into the foo stackframe”?
tagore 2017-09-09 23:34:17 So I'm suspicious of the approach. Would a set of mutually recursive functions that built a result (much like a parser) do for you?
noisesmith 2017-09-09 23:35:16 you are right about (f (g (h x))) not needing to go three deep, my bad but comp still makes things go deeper because of the way it handles varargs with self calls that generate new functions (I think? or was stuart wrong?)
hmaurer 2017-09-09 23:36:08 @noisesmith :tada: what code did you run to check that?
tagore 2017-09-09 23:36:24 You might still have to trampoline, because stack frames, but....
noisesmith 2017-09-09 23:36:30
+user=> (let [f inc g inc h inc i inc j inc k inc l inc m /] (f (g (h (i (j (k (l (m 1 0)))))))))
nil clojure.main/repl/fn--9954 (main.clj:260) clojure.main/repl/read-eval-print--9945 (main.clj:242) clojure.main/repl/read-eval-print--9945/fn--9948 (main.clj:242) clojure.core/eval (core.clj:3183) clojure.core/eval (core.clj:3187) clojure.lang.Compiler.eval (Compiler.java:6941) clojure.lang.Compiler.eval (Compiler.java:6978) user/eval21 (NO_SOURCE_FILE:9) user/eval21 (NO_SOURCE_FILE:9) clojure.core// (core.clj:1012) clojure.core// (core.clj:1019) clojure.lang.Numbers.divide (Numbers.java:158) ArithmeticException Divide by zero +user=> (pst) ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)
hmaurer 2017-09-09 23:36:37 @noisesmith yes I think that’s right; comp uses reduce after 2 args so that will generate extra stackframes, right?
noisesmith 2017-09-09 23:36:53 I think so - checking now
hmaurer 2017-09-09 23:37:16 oh wait, actually it might not…
noisesmith 2017-09-09 23:38:05
+user=> (let [f inc g inc h inc i inc j inc k inc l inc m /] ((comp f g h i j k l m) 1 0))
now I'm back to my original thought that `comp` avoids creating more stack frames, but I would be surprised if <@stuartsierra> was wrong about this
nil clojure.main/repl/read-eval-print--9945 (main.clj:242) clojure.main/repl/read-eval-print--9945/fn--9948 (main.clj:242) clojure.core/eval (core.clj:3183) clojure.core/eval (core.clj:3187) clojure.lang.Compiler.eval (Compiler.java:6941) clojure.lang.Compiler.eval (Compiler.java:6978) user/eval30 (NO_SOURCE_FILE:13) user/eval30 (NO_SOURCE_FILE:13) clojure.core/comp/fn--6808 (core.clj:2543) clojure.core// (core.clj:1012) clojure.core// (core.clj:1019) clojure.lang.Numbers.divide (Numbers.java:158) ArithmeticException Divide by zero +user=> (pst) ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)

Related Questions