Why are consecutive spaces in the result of an evaluated expression collapsed in Light Table? - lighttable

Light Table appears to collapse multiple consecutive spaces.
Expected behavior: (str "hello " "there") => "hello there"
Actual behavior: (str "hello " "there") => "hello there"

I assume this is "just" a display issue related to light table's HTML-based platform. You can confirm this by evaluating these expressions:
(= "hello there" (str "hello " "there")) ; true
(= "hello there" (str "hello " "there")) ; false

Related

Convert input string into Morse Code with Clojure

I am trying to develop a converter that takes an input string and converts it into morse code through a Morse Library map, while also respecting functional programming rules. Sorry for any clarification issues, I am new to Stack Overflow
(ns clojureassignment.core
(:gen-class))
(require '[clojure.string :as str])
;this function is where the converter is developed
(defn morse->ASCI
[x]
(def morse_Library {:A ".-":B "-...":C "-.-.":D "-..":E ".":F "..-.":G "--.":H "...."
:I "..":J ".---"
:K "-.-":L ".-..":M "--" :N "-.":O "---":P ".--.":Q "--.-":R ".-."
:S "...":T "-":U "..-":V "...-":W ".--":X "-..-":Y "-.--":Z "--.."
:0 "-----":1 ".----":2 "..---":3 "...--":4 "....-":5 "....."
:6 "-....":7 "--...":8 "---..":9 "----."})
(let [stringVector (str/upper-case(seq x))] ;divide the string into a sequence of characters
;trying to create iteration of the input where it checks if its value is found in the morse library
(doseq [[stringVector] (morse_Library)]
(if (= stringVector (morse_Library)
(do (println(str (key morse_Library))))
(do (println("characters not found"))))
)))
(print (str/upper-case stringVector))
)
(defn -main
[& args]
(println "ASCII to Morse Converter.")
(println "Make sure to include whitespaces after each ASCII character. Add String")
(def stringInput (read-line))
(println stringInput )
(morse->ASCI stringInput)
)
(-main)
I tried to create a "doseq" iteration where it checks if the value is found in the map.
Good things:
using a map for your morse translation; maps are also functions and
make it easy to write a transformation like this
Not so good things:
don't def inside other def:s - it's used to define namespace
global things and it is not like var or auto or whatever you
know from other languages
don't use keywords as map keys, if you don't plan to use them like
that; Clojure takes pretty much anything as key. So in your case
use chars
don't seq and then upper-case - wrong order - this will give you
the .toString() from a sequence of characters otherwise
don't name things all the same (stringVector)
doseq is for side-effects; you don't want your morse-code function
to do side-effects (you maybe want to print it later); in functional
programming you shift your side-effects to the edges - this way your
code becomes easier to test and reason about
you pretty much never need :gen-class
use the correct way to require in the
namespace
Clojure prefers snake-case over camelCase
(random rant: if you are using tutorialpoint (I assume this from several
things going wrong here and having them seen there) to learn Clojure: do
yourself a favour and look for another resource; as of now they don't
teach idiomatic Clojure!
Make your transformation a pure function:
upper-case the input
make a seq from it (this now is a sequence of chars) - but you don't
actually have to do this, because the next step will take care of it
map the look-up-table with your designated fallback over each char
join the result
This will look something like this:
(def morse {\A ".-" ,,, })
(->> input
(str/upper-case)
(map #(morse % "???"))
(str/join))
;; preparation of morse map
(ns morse
(:require [clojure.string :as str]))
;; I stole morse dictionary from some python code in:
;; https://www.geeksforgeeks.org/morse-code-translator-python/
(def s "{ 'A':'.-', 'B':'-...',
                    'C':'-.-.', 'D':'-..', 'E':'.',
                    'F':'..-.', 'G':'--.', 'H':'....',
                    'I':'..', 'J':'.---', 'K':'-.-',
                    'L':'.-..', 'M':'--', 'N':'-.',
                    'O':'---', 'P':'.--.', 'Q':'--.-',
                    'R':'.-.', 'S':'...', 'T':'-',
                    'U':'..-', 'V':'...-', 'W':'.--',
                    'X':'-..-', 'Y':'-.--', 'Z':'--..',
                    '1':'.----', '2':'..---', '3':'...--',
                    '4':'....-', '5':'.....', '6':'-....',
                    '7':'--...', '8':'---..', '9':'----.',
                    '0':'-----', ', ':'--..--', '.':'.-.-.-',
                    '?':'..--..', '/':'-..-.', '-':'-....-',
                    '(':'-.--.', ')':'-.--.-'}")
;; and transformed it using clojure to a clojure map:
(def m (read-string (str/replace
(str/replace
(str/replace
(str/replace s
"\n" "")
"                    " " ")
":" " ")
"'" "\"")))
;; now `m` contains the string-to-morse map
The actual answer starts here:
;; convert any text string to a morse string:
(defn string-to-morse [s]
(str/join " "
(map #(get m (str/upper-case %)) (str/split s #""))))
;; and this function can transform the output back to text:
(defn morse-to-string [morse-string]
(let [ms (zipmap (vals m) (keys m))]
(str/join (map #(get (zipmap (vals m) (keys m)) % " ")
(str/split morse-string #" ")))))

Clojure: NullPointerException at recursive function [duplicate]

Why does the following Clojure program throw a NullPointerException?
user=> (defn x []
"Do two things if the expression is true."
(if true ((println "first expr") (println "second expr")) false))
user=> (x)
first expr
java.lang.NullPointerException (NO_SOURCE_FILE:0)
second expr
This is a simplified version of my actual use case, where I want to execute maybe three statements (pull values from the DB) before returning a map - {:status 200, :body "Hello World"} inside of the branch.
It is trying to treat the result of the first println as a function to call on the second println function.
You need a do.
(defn x []
"Do two things if the expression is true."
(if true (do (println "first expr") (println "second expr")) false))
(x)
The do special form (progn in CL, begin in Scheme) executes each of its arguments in sequence and returns the result of the last one.
If nil is ok as a return value in the else case, consider using when which has an implicit do block:
(defn x []
"Do two things if the expression is true."
(when true
(println "first expr")
(println "second expr")))
Not that it matters in your particular case, but do know the difference between (do ...) which will load each form in its own classloader, and an empty let form (let [] ...) which evaluates the whole form in a single classloader.

Output prompts are on top of each other

I am reading the book Practical Common Lisp. I typed the simple CD database shown in Chapter 3. See below. When I run the (add-cds) program the result is a prompt containing two prompts on top of each other (more precisely, one prompt after another, on the same line):
(add-cds)
=> Title: Artist:
Why is it doing this? The program should give me the Title: prompt first and the Artist: prompt only after I've typed in a value for Title: followed by newline. I am pretty sure that I typed in the program faithfully. How do I fix this?
(defvar *db* nil)
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defun add-record (cd) (push cd *db*))
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun prompt-for-cd ()
(make-cd
(prompt-read "Title")
(prompt-read "Artist")
(or (parse-integer (prompt-read "Rating") :junk-allowed t) 0)
(y-or-n-p "Ripped [y/n]")))
(defun add-cds ()
(loop (add-record (prompt-for-cd))
(if (not (y-or-n-p "Another? [y/n]: ")) (return))))
What's happening is that the newline after (add-cds) is being left in the input stream (because the REPL stops reading as soon as it sees the matching close parenthesis), so the first read-line is reading that as a blank line and returning immediately. Call clear-input before calling read-line to ignore this and wait for new input.
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(clear-input *query-io*)
(read-line *query-io*))

CL-PPCRE Unicode Property

I am trying to find a solution to this simple Perl code using the CL-PPCRE Library:
if (/\p{Space}/){
print "This string has some spaces\n";
}
I am a newbie to CL-PPCRE and tried:
(scan "\\p{\\#Space}" "The String has some white spaces")
; I got an error saying property #/Space doesn't exists.
How can I execute an equivalent?
The perl regexp /\p{Space}/ matches more than just " ". cf \p{} docs
One approach is to just use the \s expression:
(cl-ppcre:scan "\\s" (format nil "hi~Cthere" #\return))
To use the whole unicode Space class:
(ql:quickload :cl-unicode)
(cl-ppcre:scan "\\p{Space}" (format nil "hi~Cthere" #\return))
See Unicode properties in the CL-PPCRE docs.
The cl-ppcre library does not require you (at least for space) to use any special constant.
(if (cl-ppcre:scan " " "alle meine entchen")
(FORMAT T "Does have spaces~%")
(FORMAT T "Does not have spaces~%"))
> Does have spaces
(if (cl-ppcre:scan " " "allemeineentchen")
(FORMAT T "Does have spaces~%")
(FORMAT T "Does not have spaces~%"))
> Does not have spaces
will do the trick.

Why does the map key not retrieve the value that can be plainly seen in the map?

The following key :GIC-ID won't return its value "999-99-9999". I am trying to figure out why.
Here are the keys -- the first row containing column names of a .csv report. The output is formatted to prevent scrolling:
["AGY/DIV " "STS" "GIC-ID " "LAST-NAME " "FIRST-NAME "
"COVERAGE DESCRIPTION "
"PREMIUM " "RUN-DATE" "BIL MO "]
Here is the data doctored for privacy (output formatted to prevent scrolling):
["666/0010" "ACT" "999-99-9999" "MARGE " "SIMPSON "
"YE OLD PILGRIM FAMILY - INSURED "
"0000.00" "123456789" "99999enter code here"]
I get the first column containing the keys/column headers and the data created with the following including the zipping together of the column names with what will be each row of data.
(def gic-csv-inp (fetch-csv-data "billing_roster.csv"))
(def gic-csv-cols (first gic-csv-inp))
(def gic-csv-data (rest gic-csv-inp))
(def zm2 (zipmap (map #(keyword %1) gic-csv-cols) (first gic-csv-data)))
Now the following keys and data, pulled from a similar but different report, work just fine:
:Employee_SSN "999-99-9999"
That is I can extract the value of the key.
There must be something wrong with the keys, and I can certainly correct those, like removing spaces and so on, but I am not sure what is wrong.
Thanks.
Edit:
The answer to my question is to trim spaces like this:
(:require [clojure.string :as cstr])
.
.
.
(def zm2 (zipmap (map #(keyword (cstr/trim %1)) gic-csv-cols)
(first gic-csv-data)))
Trimming spaces does work
(def zm2 (zipmap (map #(keyword (re-find #"[^\s]*" %1)) gic-csv-cols) (first gic-csv-data)))
=> (zm2 :GIC-ID)
"999-99-9999"
[^\s]* being a regexp to match all non-whitespace characters

Resources