Problem statement:
Write a program that converts all given temperatures from a given input temperature scale to a given output temperature scale. The temperature scales to be supported are Kelvin, Celsius, Fahrenheit, Rankine, Delisle, Newton, Rømer, Réaumur.
Synopsis: tempconv INPUT_SCALE OUTPUT_SCALE [TEMPERATURE]...
The INPUT_SCALE and OUTPUT_SCALE shall be given as follows:
Kfor KelvinCfor CelsiusFfor FahrenheitRfor RankineDfor DelisleNfor NewtonRøfor RømerRéfor Réaumur.
Example:
tempconv K C 0 273.15 373.15
-273.15
0.0
100.0
My solution in Clojure:
#!/usr/bin/env -S clojure
(defrecord TemperatureConverter [toKelvin fromKelvin names])
(def converters [
(TemperatureConverter. (fn [kelvin] kelvin) (fn [kelvin] kelvin) #{"K" "k"})
(TemperatureConverter. (fn [celsius] (+ celsius 273.15)) (fn [kelvin] (- kelvin 273.15)) #{"°C" "C" "c"})
(TemperatureConverter. (fn [delisle] (- 373.15 (* delisle (/ 2 3)))) (fn [kelvin] (/ (* (- 373.15 kelvin) 3) / 2)) #{"°De" "De" "DE" "de"})
(TemperatureConverter. (fn [fahrenheit] (+ fahrenheit (* 459.67 (/ 5 9)))) (fn [kelvin] (- (* kelvin (/ 9 5)) 459.67)) #{"°F" "F" "f"})
(TemperatureConverter. (fn [newton] (+ (* newton * (/ 100 33)) 273.15)) (fn [kelvin] (/ (* (- kelvin 273.15) 33) 100)) #{"°N" "N" "n"})
(TemperatureConverter. (fn [rankine] (* rankine (/ 5 9))) (fn [kelvin] (/ (* kelvin 9) 5)) #{"°R" "R" "r"})
(TemperatureConverter. (fn [réaumur] (+ (* réaumur (/ 5 4)) 273.15)) (fn [kelvin] (/ (* (- kelvin 273.15) 4) 5)) #{"°Ré" "°Re" "Ré" "RÉ" "ré" "Re" "RE" "re"})
(TemperatureConverter. (fn [rømer] (+ (/ (* (- rømer 7.5) 40 ) 21) 273.15)) (fn [kelvin] (+ (/ (* (- kelvin 273.15) 21) 40) 7.5)) #{"°Rø" "°Ro" "Rø" "RØ" "rø" "Ro" "RO" "ro"})
])
(defn getconv [name] (first (filter #(contains? (.names %) name) converters)))
(if-let [[inputScale outputScale & args] *command-line-args*]
(do
(def toKelvin (. (getconv inputScale) toKelvin))
(def fromKelvin (. (getconv outputScale) fromKelvin))
(doseq [arg args]
(println (fromKelvin (toKelvin (read-string arg))))
)
)
)
I seek to understand if there is anything that can be improved, especially if there is some smart way to use a macro to simplify the code that I missed.
Note:
- For now, error handling (user inputs text instead of a number, or an unknown scale) is not of concern.
- I'm aware that my "brace style" with closing parentheses on separate lines is not the usual Lisp/Clojure style that would collect them at the end of the last line. I prefer this way because it causes less noise in diffs in version control.
- I'm aware that the lines defining the temperature converters are long. I usually don't like long lines, but in this case, a tabular layout makes the source code easier to read.