简体   繁体   中英

ClojureScript equivalent for this JavaScript code

I am trying to use esrecurse in my ClojureScript code, I have a working JavaScript snippet that looks like this

esrecurse.visit(ast, {
  Literal: console.log
});

and I'm trying to come up with the equivalent for ClojureScript, but whenever I run it esrecurse.visit is not called

#(.visit esrecurse % (js-obj "Literal" (fn [node] node)))

where % is the AST. I am not sure what I'm doing wrong honestly, I've also tried passing the second argument in a different way, like

#(.visit esrecurse (first (vals %)) {:Literal (fn [node] node)})

without success.

I'm invoking mutate? like this

(defn mutate?
  "applies a mutation to the ASTs,
  returns the mutated, or non mutated, ASTs"
  [asts]
  (map
   #(.visit esrecurse % #js {:Literal print})
   asts))

(mutate? (reader/to-ast (reader/read "./test/example-project/lib")))

But with both this version and mine I still don't get anything, I also tried passing identity instead of print but I just got (nil) as result.

This works fine for me with a mocked implementation of esrecurse.visit .

(defn visit [ast]
  (.visit esrecurse ast #js {:Literal print}))

(visit #js {:type "Literal"})

;; prints #js {:type "Literal"}

And the mocked code:

var esrecurse = {
  visit(node, visitor) {
    visitor.Literal(node);
  }
}

Here's a less verbose version of the same idea.

 #(.visit esrecurse % #js {:Literal print}))

Verify that you're calling the function correctly, because your first implementation looks fine to me and works in place of either of the above functions.

At a guess, I'd say the reason you're not seeing anything happen in your second example is because Clojure's sequences are lazy —meaning your computation won't be applied until you ask for the result.

These lazy sequences ( take returns one too) are only evaluated when something calls doall , dorun or doseq on them.

This happens under the hood if you call print or evaluate an expression which returns a lazy sequence in a repl.

You can try forcing the evaluation of your lazy expression with doall .

(doall
  (mutate? (reader/to-ast (reader/read "./test/example-project/lib"))))

This doesn't feel natural and that's the point. As a reasonably pure functional programming language, Clojure expects you to mostly write functions without side effects.

This is an example of where JavaScript interop can be painful, as esrecurse.visit doesn't actually return a value, making the call to map return a sequence of nil values. I would be tempted to pull the anonymous function out and redefine it to always return the AST it was passed.

(defn visit [ast]
  (.visit esrecurse ast #js {:Literal print})
  ast)

(defn mutate?
  "applies a mutation to the ASTs,
  returns the mutated, or non mutated, ASTs"
  [asts]
  (map visit asts))

(doall
  (mutate? (reader/to-ast (reader/read "./test/example-project/lib"))))

And just as a heads up, mutate? would be the convention for naming a function which returns a boolean. Maybe you meant mutate! instead, which would be the convention for a function that may perform side effects?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM