Addition of two numbers by taking user input - clojure

How to add two numbers by taking user input?
(println "What's first?")
(let [num1 ( read-line)]
(println (str num1)))
(println (str num1))
(println "What's sec?")
(let [num2 (read-line)]
(println (str num2)))
(println str(+ num1 num2)))

(let [num1 (do (println "What's first?") (Integer/parseInt (read-line)))
num2 (do (println "What's sec?") (Integer/parseInt (read-line)))]
(println (+ num1 num2)))
do blocks return result of evaluation of last expression. Then parse the result of read-line to a string and assign it to respectively num1 and num2, then add the numbers and print the result.
Note there's no need to convert the result to a string before passing to println as you tried. If you would like to do it the str should be within the parentheses: (str (+ num1 num2)).

Related

Compact way in Clojure to print a variable number of command line arguments?

I'm a newbie to Clojure. I think I'm trying to solve this procedurally and there must be a better (more functional) way to do this in Clojure...
The -main function can receive a variable number of 'args'. I would like to print them out but avoid an IndexOutOfBoundsException. I thought I could mimic Java and use a case fall-through to minimize the code involved, but that didn't work:
(defn -main [& args]
(println "There are" (str (count args)) "input arguments.")
(println "Here are args:" (str args))
(let [x (count args)]
(case x
(> x 0) (do
(print "Here is the first arg: ")
(println (nth args 0)))
(> x 1) (do
(print "Here is the 2nd arg: ")
(println (nth args 1)))
(> x 2) (do
(print "Here is the 3rd arg: ")
(println (nth args 2))))))
(doseq [[n arg] (map-indexed vector arguments)]
(println (str "Here is the argument #" (inc n) ": " (pr-str arg))))
map-indexes is like map but adds index number in the beginning.
So it goes item by item through arguments, packs index and item into a vector and by destructruing index number and item are mapped to [n arg].
Since clojure begins counting from 0, you use (inc n) to begin counting from 1. pr-str is pretty print string. The str joins all string components together.
there is also a handy formatting facility in clojure's core library: cl-format, which is the port of common lisp's format syntax. It includes a nice way to print out collections:
(require '[clojure.pprint :refer [cl-format]])
(let [args [:a :b :c :d]]
(cl-format true "~{here is the ~:r arg: ~a~%~}"
(interleave (rest (range)) args)))
;; here is the first arg: :a
;; here is the second arg: :b
;; here is the third arg: :c
;; here is the fourth arg: :d
some more information about what format can do is here

Simple guessing game in Clojure not working properly

I am new to Clojure. As part of practice, I wrote a simple guessing game where the user has to guess a random number chosen by the program between 1-100. I got a basic version working (code snippet 1). Now I want to improve on this by allowing the user to enter an integer from 1 to 100. However the code that I wrote to avoid the user from entering a string is not working (code snippet 2) but the code is not working, no matter what I try.
Code snippet 1 (working)
(ns guessing-game2.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))
(recur (inc times))))))))
Code snippet 2 (not working)
(ns guessing-game.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (and (integer? guess)
(< guess 100))
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))))
(print "Please enter a number")
(recur (inc times))
)
))))
you need to recur outside of the if
(ns guessing-game.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (and (integer? guess)
(< guess 100))
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))))
(print "Please enter a number")) ;; <-- moved bracket to here
(recur (inc times))
))))

How do I join string set into a single string with positions prepended?

Assume I have this
(def base ["one" "two" "three"])
I want to convert it to:
1. one
2. two
3. three
(aka 1. one \n2. two \n3. three)
with join, I am not sure I can append a counter before joining:
(clojure.string/join " \n" base)
=> "one \ntwo \nthree"
and with doseq or similar, plus an atom, I do get individual strings but then will have to concatenate later on, something like
(def base ["one" "two" "three"])
(def pos (atom 0))
(defn add-pos
[base]
(for [b base]
(do
(swap! pos inc)
(str #pos ". " b))))
(let [pos-base (add-pos base)]
(clojure.string/join " \n" pos-base))
=> "1. one \n2. two \n3. three"
While it works, I don't know if using an atom with a for statement is he best way to do this, it doesn't look very clojure-esque.
Is there a better way to do this please?
That's a job for keep-indexed:
user> (keep-indexed #(str (inc %1) ". " %2) ["one" "two" "three"])
("1. one" "2. two" "3. three")
user> (clojure.string/join "\n"
(keep-indexed
#(str (inc %1) ". " %2)
["one" "two" "three"]))
"1. one\n2. two\n3. three"
A minor alternative to schaueho's keep-indexed would be map-indexed (spotting a pattern?)
(def base ["one" "two" "three"])
(defn numbered-list [s]
(->> s
(map-indexed #(str (inc %1) ". " %2))
(interpose \newline)
(apply str)))
(numbered-list base) ; => "1. one\n2. two\n3. three"
Clearly a job for interleave.
(->> (interleave (rest (range)) (repeat ". ") base (repeat " \n"))
(apply str))
;-> "1. one \n2. two \n3. three \n"

wrong number of arguements clojure

I'm building a program that's meant to allow users count either the number of letters or number of words in a string, however when running the program through the cmd, I'm getting a clojure.lang.ArityException, wrong number of args (1) passed to : core/-main/counter--5333
My code is
;;Create a GUI which allows user to input a string and to select "word count" or "letter count". When "Start" is clicked pass both the string and either (wordCount [string x]) or (letterCount [string x]) to
;;declare functions as variables
;;show function that takes functions as parameters
;;show function that returns another function
(ns firstclass.core
(:gen-class)
(:use seesaw.core))
(defn -main
[& args]
(def strInput (input "Please enter a string to be evaluated"))
(def groups (button-group))
(def s (selection groups))
(def letterRadio (radio :text "Letter" :group groups))
(def wordRadio (radio :text "Word" :group groups))
(defn letterCount
[string]
(loop [characters string
a-count 0]
(if (= (first characters) \a)
(recur (rest characters) (inc a-count))
a-count)))
(defn wordCount
[string]
(loop [characters string
a-count 0]
(if (= (first characters) \a)
(recur (rest characters) (inc a-count))
a-count)))
(def counter (fn [fn x, string strInput] (x [strInput])))
(defn handler [event]
(if-let [s letterRadio]
(counter [letterCount, strInput]))
(if-let [s wordRadio]
(counter [wordCount, strInput])))
(def start (button :text "Start Count" :listen [:action handler] ))
(def panel
(flow-panel :items [strInput, letterRadio, wordRadio, start]))
(invoke-later
(-> (frame :content panel :on-close :dispose)
pack! show!)))
for your definition of counter
(def counter (fn [fn x, string strInput] (x [strInput])))
you have a function of four arguments
in the handler function, you call it with one argument:
(counter [letterCount strInput])
from context I assume that you meant to define counter as having two arguments, and you meant to call it on two arguments, rather than a single vector of two items.
(def counter (fn [x strInput] (x strInput)))
...
(counter letterCount strInput)
Also, it's better to use defn to define functions, rather than def and fn separately
(defn counter [x strInput] (x strInput))

Clojure say-hi with varargs

Input: "Michael" "Julia" "Joe" "Sam"
Output: Hi, Michael, Julia, Joe, and Sam. (pay attention to the commas and the word "and")
Input: nil
Output: Hi, world.
Here is my first attempt:
(defn say-hi [& name]
(print "Hi," name))
user> (say-hi "Michael")
Hi, (Michael)
nil
user> (say-hi "Michael" "Julia")
Hi, (Michael Julia)
nil
Question:
How to implement default: (no input, say "Hi World!")
How to get rid of the parents around names in output?
How to implement the commas separation and add the conjunction word "and"?
First off, Clojure supports multi-arity functions, so you could do something like this to achieve default behaviour:
(defn say-hi
([] (say-hi "World"))
([& names] ...))
Then, what you want is to take a seq and join all the strings it contains together, using ", " in between. The clojure.string namespaces contains lots of string manipulation functions, one of them being clojure.string/join:
(require '[clojure.string :as string])
(string/join ", " ["Michael", "Julia"])
;; => "Michael, Julia"
But the last element of the seq should be concatenated using " and " as a separator, so you'll end up with something like this:
(require '[clojure.string :as string])
(defn say-hi
([] (say-hi "World"))
([& names]
(if (next names)
(format "Hi, %s, and %s!"
(string/join ", " (butlast names))
(last names))
(format "Hi, %s!" (first names)))))
Note that you have to differentiate between the single- and multi-name cases and (next names) basically checks whether the seq contains more than one element. (You could achieve the same by adding another arity to the function.)
(say-hi)
;; => "Hi, World!"
(say-hi "Michael")
;; => "Hi, Michael!"
(say-hi "Michael" "Julia" "Joe" "Sam")
;; => "Hi, Michael, Julia, Joe, and Sam!"
You can use clojure.string/join:
(use '[clojure.string :only [join]])
(defn sentencify [& elems]
(->>
[(join ", " (butlast elems)) (last elems)]
(remove empty?)
(join " and ")))
(defn say-hi [& name]
(print "Hi," (if name
(sentencify name)
"World!")))
A concise solution:
(defn say-hi [& names]
(let [names (case (count names)
0 ["world"]
1 names
(concat (butlast names) (list (str "and " (last names)))))]
(->> names, (cons "Hi"), (interpose ", "), (apply str))))
(say-hi)
;"Hi, world"
(say-hi "Michael")
;"Hi, Michael"
(say-hi "Michael" "Julia" "Joe" "Sam")
;"Hi, Michael, Julia, Joe, and Sam"
For long lists of names, you would want to eschew count, last, and butlast, maybe by pouring names into a vector first.
To print (as the question does) rather than return the formatted string, append print to the final form:
(->> names, (cons "Hi"), (interpose ", "), (apply str), print)