Order changes when using print vs println - clojure

I've been experimenting with creating monads in clojure so I can separate my pure code from my impure code more thouroghly, and I've stumbled upon something strage with ordering.
When using the following code for a minimum use-case, the desired output is for it to print "Please enter your name: " to the screen and then take a single line of input, which is then printed back out to the screen. The code below is what should be able to acccomplish this:
;; IO Monad definitions
(defn io-bind
[mv mf]
(fn []
(let [val (mv)
f (mf val)]
(f))))
;; Monadic functions
(defn io-print
[msg]
(fn []
(print msg)))
(defn io-read-line
[_]
(fn []
(read-line)))
;; Entry point
(defn -main
"I don't do a whole lot ... yet."
[& args]
((-> (io-print "Please enter your name: ")
(io-bind io-read-line)
(io-bind io-print))))
I've experienced a hitch with this however, in that it will first poll for input from the user using (read-line) and only afterwards will it then print "Please enter your name: ".
In larger examples, it will still perform all of the visible IO actions in the proper order, for example in this case it does print out "Please enter your name: " before it prints out what you inputted, yet it still requests that input first.
The strangest part however is that the instant I replace print with println in io-print it does all of the ordering as intented, regardless of circumstance.
Why might this be occuring? Is there some way that print is lazy that println is not, for example?

You need to add the following after the print:
(flush)
println will implicitly flush the output to the screen, so that is why you are seeing different behavior than with print.
Please see https://clojuredocs.org/clojure.core/flush for more info, as also the source code for all the details.

Related

How to simulate user input?

I know that one can simulate a user's input by wrapping the (read-line) function in with-in-str and then passing your input programmatically like this:
(with-in-str "punit naik" (println (read-line)))
This will of course print punit naik to the console.
But the problem is, I have a function which runs recursively and continuously asks for user input in it's iterations.
And I want to write a test case for that function. How do I achieve this?
read-line reads one line at a time. You can prepare a string that contains all of the lines that need to be read separated with new line:
(with-in-str
"a\nb\nc"
(loop []
(if-let [line (read-line)]
(do
(println "Line was" line)
(println "Recurring")
(recur))
(println "No more lines"))))
This prints:
Line was a
Recurring
Line was b
Recurring
Line was c
Recurring
No more lines

Clojure looping based on user input

In Clojure I want to create a function that would continually ask the user for an option, execute some code depending on the option, and then quit when the user’s option is “q”.
I am comfortable will all of the various Clojure forms that work with sequences, and I could certainly finagle a Java-like solution to the above, but I cannot figure out how to do this in a “clojuresque” manner.
Thanks,
Jeffrey S
Something like this should do the job:
(defn main-loop []
(case (read-line)
"q" nil
"a" (do (println "got a command!") (recur))
"b" (do (println "got b command!") (recur))
(do (println "got invalid command!") (recur))))

Output with println in clojure on Hackerrank

Hi I am starting to write clojure code and practicing Hackerrank questions.
The problem requires me to take input as
2
RGRG
BGYG
where 2 is number of test cases followed by 2 strings.
I have written following code to take input and print the output of it where fullballs? is my function :
(defn Start [FuncToCall inputParse outputParse]
(let [lines (line-seq (java.io.BufferedReader. *in*))
input (rest lines)
times (first lines)]
(for [i (range (Integer. times))]
(outputParse (FuncToCall (inputParse (nth input i)))))
))
(Start fullballs?
(fn [x] x)
(fn [x]
(if x
(println "True")
(println "False"))
x))
However, Hackerrank says that nothing gets printed on the stdout.
Also when i am trying it int cider repl it is not something like usual
(False
False
false false)
for my two test cases..
Is this problem with for or where is my code wrong ?
for is lazy. This means that unless and until you force evaluation of the result, side effects will not be executed.
The reason this works in your REPL is that it tries to print out the result of your function. This forces evaluation of the lazy sequence produced by for.
Use doseq instead.
For further reading.
I don't understand the second half of your question: "It is not something like usual for my two test cases."

How can I lazily evaluate read-line to gather input?

(The following was originally a homework assignment, but I'm trying it in a new language.)
In a short Clojure program, I attempt to generate a lazy sequence of inputs (from the command line) and from them calculate three character values. I would assume that, possibly depending on how Clojure chose to evaluate my let bindings, this ought to produce a prompt series like the following:
$ clj lazy-prompts.clj
Enter value #1: 32
Enter value #3: 162
Enter value #2: 12
Enter value #4: 118
a A 5
Instead, the program begins and hangs infinitely with no prompts. I tried eagerly evaluating the for expression by wrapping it in dorun, but that did not change the outcome.
Why does the following program produce no input prompts?
(use '[clojure.java.io :only (reader)])
(def of-input
(for [value-number [1 2 3 4]]
(dorun
(print (str "Enter encrypted value #" value-number))
(read-line)
)))
(let [value-1 (nth of-input 1)
value-2 (nth of-input 2)
value-3 (nth of-input 3)
value-4 (nth of-input 4)]
(let [a (/ (+ value-1 value-3) 2)
b (/ (+ value-2 value-4) 2)
c (- value-4 b)]
(println (char a) (char b) (char c))))
First, you should replace dorun with do. The former expects a seq as its first or second argument and forces it.
After that change, the code more or less runs correctly. What you observe as "hanging" is actually waiting for your input. One of the problems is, that you don't see the prompts (yet). They actually show, but only after you enter four values. How do you fix that? I don't know, I always thought that having side effects in a lazy sequence is a bad idea, so I never do that.
The other problem is, that read-line returns strings and you're using them as numbers. You'll have to convert them first.
P.S. "for" in clojure is not a for-loop, it is a list comprehension.
print does not flush the output, so you don't see the prompts immediately. Either use println or call flush explicitly, like so:
(def of-input
(for [value-number [1 2 3 4]]
(dorun
(print (str "Enter encrypted value #" value-number))
(flush)
(read-line)
)))

How to get user input in Clojure?

I'm currently learning clojure, but I was wondering how to get and store user input in a clojure program. I was looking at the clojure api and I found a function called read-line, however I'm not sure how to use it if it's the right function to use...
Anyhow, how do you get user input in clojure ?
read-line is the correct function..
(println (read-line))
..would basically echo the users input:
Clojure 1.0.0-
user=> (println (read-line))
this is my input
this is my input
To use it in an if statement, you'd probably use let:
(let [yayinput (read-line)]
(if (= yayinput "1234")
(println "Correct")
(println "Wrong")))
Hope that's enough to get you started, because that's about the limit of my Clojure knowledge!
Remember also that you have access to all of Java ...
OK so perhaps I should present some examples ... my clojure skills are not good so these examples may need a bit of tweaking.
The System.console() way:
(let [console (. System console)
pwd (.readPassword console "tell me your password: ")]
(println "your password is " pwd))
The BufferedReader way:
(print "give me a line: ")
(let [reader (java.io.BufferedReader. *in*)
ln (.readLine reader)]
(println "your line is " ln))
My point is that one can leverage knowledge of Java, and Java itself, in Clojure. It's one of its principal, advertised strengths.
Wonder what would my score have been if the question were about user input from a GUI!
By the way, you could use JOptionPane to put up a little GUI to get user input ...
read-line is used to get user input and use let to bind it to some variable.
For example : if you want to read user ID and password from user and display it, you could use the following piece of code
(defn print-message [pid pw]
(println "PID : " pid)
(println "PW : " pw))
(defn inp[]
(println "Enter your PID and password")
(let[pid (read-line) pw (read-line)]
(print-message pid pw) ))