简体   繁体   中英

Converting the Java concept into Clojure

I am pretty new with Clojure. I have one Java method including a boolean variable and I want to rewrite this method to use it with the same functional in Clojure as well. But I couldn't find how to set the boolean value true and false in run-time in Clojure.

The following snippet basically emphasize only the boolean part, It is difficult to think for me to write this in a functional way.

int calculate(...){
  int y = 0;
  boolean flag = false;
  foreach(...){
     if(!flag){
        y = 1;
        flag = true;
     }
     else{
        y = -1;
        flag = false;
     }
  }
  return y;
} 

Here is the my first attempt in Clojure:

(defn calculate [...]
    ( ??flag?? -> I do not know which macro I should use over here
      (doseq [x ...]
        (if (false? flag) (do 1 (set the flag true)) 
           (do -1 (set the flag false)))))

How can I implement the same concept in Clojure?

For the Java code you have, it looks like the simplest way to translate it into Clojure would be to skip all the iterating and just return the final value:

(defn calculate [coll]
  (odd? (count coll)))

If you want something more elaborate I guess you could do something like

(defn calc [coll flag]
  (if (empty? coll)
    flag
    (recur (rest coll) (not flag))))

and call it with

(defn calculate [coll]
  (calc coll false))     

This kind of recursion isn't the most idiomatic style, and it's kind of crazy for this problem, but it demonstrates how instead of mutating variables you write an expression that when evaluated produces the value passed into the next iteration (see the recur call in the example above).

It would be better style to rewrite this like

(defn calculate
  ([coll flag]
    (if (empty? coll)
      flag
      (recur (rest coll) (not flag))))
  ([coll]
    (calculate coll false)))

so there's only one function name to deal with. (I left the other way in thinking it would likely be clearer to read for somebody new to Clojure.)

I second the comment suggesting you look at 4clojure . It's a good way to get practice, and once you have a solution you can learn from what other users did.

Use loop / recur to emulate iterative statements in Clojure:

(defn calculate [...]
  (loop [...
         y    0
         flag false]
    ...
    (if (false? flag)
      (recur ...  1 true)   ;; "loop with x = ..., y = 1 and flag = true"
      (recur ... -1 false)) ;; "loop with x = ..., y = -1 and flag = false"
    ... )

EDIT: let me elaborate. What I understand from your question is that you have trouble translating mutability-based (Java) code into Clojure. This is natural. Clojure is big on immutability.

One way to implement mutability in a Clojure program is to use reference types, in particular atoms . Your piece of code could be written this way in Clojure:

(defn calculate [...]
  (let [y    (atom 0)
        flag (atom false)]
    (doseq [x ...]
      (if (false? @flag)
        (do (reset! y 1)
            (reset! flag true))
        (do (reset! y -1)
            (reset! flag false))))
    (... return some function of y and flag ...)))

It works. But heavy use of atoms and side-effects is not idiomatic in Clojure; useful at times, yes, but not necessary and cumbersome compared to functional, idiomatic Clojure.

A better way to model mutability in the context of iteration is to translate it in terms of recursion, like what I did with loop / recur above.

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