There lot of Lisp-like programming language which claimed by many of people offering peace of mind in programming and powerful language to expressing idea. Yukari end up with Clojure which fond for while quite suffering when first touching (Yukari have touch Racket and Common Lisp yet still not get used).
The reason Yukari fond with Clojure is the language bit less lisp-ty and easy to grasp. Clojure aiming to reduce parentesses which nice and also keeping the benefit of Lisp intact, let say Lisp with contemporary touch.
Ultimately, Yukari pursuing thinking experience in another programming language since each language have it own culture, perspective and wisdom which enhance Yukari mind. Despite that same tool to write program, it's making you think differently, is'nt?
Meanwhile, Lisp itself quite niche in term of popularity, let alone Clojure. But Clojure have a lot of resource to learn by community and ecosystem support from Java (Multiplatform uhum 3 Billion devices run java).
(defn fib [acc x]
(if (x = 0) acc (fib (+ acc x) (- x 1))))
(defn -main []
(print UwU))
This what Clojure look like, seems programming language used by Cthulhu (pun intended). Enough the introduction, moving on.
To follow this step, Yukari assume you already installing Clojure, Leiningen (want a challange? then use Clojure tools.build for building project) and code editor that already installed with Clojure plugin to enhance developer experience (Notepad++, VSCode, Vim, Emacs: Yukari won't judge).
First create a project using :
$ lein new app <your-app-name>
Attention: do not write the dollar sign, it just indicator that it was shell command.
In this example, Yukari will use moe. Leiningen will create folder with those name, and get inside it.
Let check if the project is works fine, by running it:
$ lein run
After generation of project folder finish, find project.clj files inside it. Then in dependencies field assure you add our library that will used for making web:
:dependencies [
[org.clojure/clojure "1.12.2"]
; add this below
[http-kit "2.8.1"]
[compojure "1.7.2"]
[hiccup "2.0.0"]]
Save the file and run :
$ lein deps
To fetching thet dependecies we need from remote registry.
Now, we done setup the project. Time to code! go to src/<your-app-name>/ there
will a file name core.clj which our program entry point. The content look like this:
(ns moe.core ; (1)
(:gen-class))
(defn -main ; (2)
"I don't do a whole lot ... yet." ;(4)
[& args]
(println "Hello, World!")) ;(3)
The explanation:
moe.core, in this place we will use to import our dependencies.-main is our entrypoint function, the program will start by invoking this function.Hello, World with newline at endline.In this phase, we will learn to use Http-kit as our web server. First let we :use it:
(ns moe.core
(:gen-class)
(:use [org.httpkit.server :as s]) ; (1)
)
s, this alias help us to invoking the function. We could use :refer like (:use [org.httpkit.server :refer [run-server]]), which simple but risky to name collision. For example we go to alias.Then we create function to handle basic request for our web server.
(defn app
[req] ; (1)
{
:status 200
:headers {"Content-Type" "text/html"}
:body "UwU"
} ; (2)
)
app function to read incoming request detail.200 OK with Content-Type HTTP headers with value text/html and body response UwU (which we should put our HTML document here).Now, we bind the function with our web server function (change entrypoint like this):
(defn -main
"our web server"
[& args]
(s/run-server app {:port 8080})) ;(1)
s/run-server will start web server with app function to handle in HTTP comming connection at port 8080.Save then run the project, and open in browser http://localhost:8080.
Now, we had the web server up and running. Then we try to mapping specific function to handle certain URL request, known as routing. Let :use compojure:
(ns moe.core
(:gen-class)
(:use
[org.httpkit.server :as s]
; (1) add this below
[compojure.core :refer [defroutes, GET, context, ANY]]
))
compojure.core without alias by using :refer attribute. Case above we could use defroutes, GET, context, ANY functions without adding compojure.core/defroutes like s/run-server.Lets delete the app function and redefine it for our web server route:
(defroutes app
(GET "/ping" [] ping) ; (1)
(GET "/uwu/:name" [name] uwu-ing); (2)
)
ping function (will define it latter on), [] it to catch parameter inside route.:name paramater that will catch /uwu/yukari as {:params {:name "yukari"}}, [name] define what pattern we will catch and deliver it to uwu-ing function.Next, we define function to handle certain request (above the app defroutes).
(defn ping [req]
{
:status 200
:headers {"Content-Type" "text/html"}
:body "pong"
}
)
(defn uwu-ing [req]
(let [name (:name (:params request)))]
{
:status 200
:headers {"Content-Type" "text/html"}
:body (str "UwU to you, " (or name "visitor"))
}
)
Save and run the projects.
We at the last piece of cake. To build HTML looking view, we need to serve it as string at :body when we response the request. Let :use the library:
(ns moe.core
(:gen-class)
(:use
[org.httpkit.server :as s]
[compojure.core :refer [defroutes, GET, context, ANY]]
; (1) add this below
[hiccup.page :refer [html5]]
))
html5 function.Hiccup is library to generate HTML from Clojure pair attribute, like this.
(html5 [:section [:p "Yukari~"] [:p "code in Clojure"]])
into
<section>
<p>Yukari~</p>
<p>code in Clojure</p>
</section>
Pretty short and clean to read. Of course, this would exhausting to convert existing HTML into Hiccup format, so use html2hiccup.dev.
So let convert the uwu-ing function to use hiccup.
(defn uwu-ing [req]
(let [
name (:name (:params request)))
label (str "UwU to you, " (or name "visitor"))
]
{
:status 200
:headers {"Content-Type" "text/html"}
:body (html5
[:html
[:head
[:title label]]
[:body label]])})
Save and run the projects.
Clojure could pretty confusing at first due it eccentric way of doing thing (especially program not have introduced to lisp before), but code in Clojure easy to read and to understand.
For me, who prefer static-typing like Dart, Clojure maybe the another dynamic typing that I found interesting and got a bit grasp of why many people implement Clojure-like language such Janet and Jank.
Although, this still small portion of Clojure. There still more for Yukari to learn (and hopefuly share to Yukari's dear reader).