This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-06-26
Channels
- # babashka (63)
- # beginners (27)
- # calva (17)
- # cider (1)
- # clojure (23)
- # clojure-europe (6)
- # clojure-norway (4)
- # clojurescript (9)
- # cursive (8)
- # data-oriented-programming (9)
- # data-science (7)
- # fulcro (14)
- # graalvm (3)
- # helix (3)
- # introduce-yourself (1)
- # jobs-discuss (7)
- # membrane (40)
- # missionary (4)
- # off-topic (32)
- # pathom (60)
- # react (6)
- # releases (2)
- # shadow-cljs (4)
How can I transform the following imperative code as declarative as much as possible? Iām studying how to use declarative code (functional) to make code more readable. With the following imperative code, Iām searching for declarative expression in Clojure or Python. Starting from a seed as the last element of the list (a list of lists), I need to use the last element to generate a new element. The process should stops once the generated element matches the pattern of the decider function. The procedure to generate a new element is hard to describe. Here is the code segment to generate it:
for i in range(n):
if last[i] >= n-1:
last[i] = 0
else:
last[i] += 1
break
indices = indices + [last]
I can use the function of take-while with the decider function over the generated list of elements.
But I have not found a sub-expression to generate an element from the last element of the previous iterationās outcome.
import copy
def calculate(a, k, decider):
n = len(a)
if (k < 1 or k > n):
raise ValueError('IllegalArgument: k.')
seed = [0]*n # [0 for i in range(n)] equivalent
indices = [seed]
total = pow(n, k) -1
for j in range(total):
last = copy.copy(indices[ -1]) # indices[ -1] is just a reference to the same element of the list indices
if (decider(last)):
break
for i in range(n):
if last[i] >= n-1:
last[i] = 0
else:
last[i] += 1
break
indices = indices + [last]
return indices
indexes = calculate(['a', 'b', 'c', 'd'], 3, lambda i: (i[0] == 1 and i[1] == 1 and i[2] == 0))
print(indexes)
It should produces:
[[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0]]
If you rely on sequential generation then you may still want to have iteration.
I think for your "generate a new element" list creation you could use iterate
ant take-while
.
And for the outer for j in range(total):
you could use reduce
and then terminate early using reduced
.
Also in Clojure you wouldn't need to do any copies yourself as it's handled for you.
Thanks for the hints! Here is my attempt to rewrite in declarative expression:
(defn calculate [a k decider]
(let [decider (fn [ [ a b c & rst]]
(and (= 1 a) (= 1 b) (= 0 c)))
f (fn [lst upper]
(if (empty? lst)
[]
(let [ [ fst & rst] lst]
(if (>= fst upper)
(concat [0] (f rst upper))
(concat [(inc fst)] rst)))))
pow (fn [x n]
(reduce * (repeat n x)))
n (count a)
seed (for [i (range n)] 0)
total (pow n k)]
(if (or
(< k 1)
(> k n))
(throw (Exception. "IllegalArgument: k."))
(reduce (fn [a v]
(let [_last (last a)]
(if (decider _last)
(reduced a)
(conj a (f _last (dec n))))))
[seed] (range total)))))
(calculate ['a' 'b' 'c' 'd'] 3 (fn [[fst snd thd & rest]] (and (= fst 1)
(= snd 1)
(= thd 0)))
It yields the same:
[(0 0 0 0) (1 0 0 0) (2 0 0 0) (3 0 0 0) (0 1 0 0) (1 1 0 0)]
Thanks again! Please help to improve the code.I suggest to split it into two or three different functions :thinking_face:
You meant take out the inline lambda function as separate ones outside of the function calculate?
@U2QGRCMSM I actually didn't understand what the code should do. Can you explain what it's expected of it, so maybe I can show an option tomorrow?
I have no idea what the function does but what I DO know is that all functions in your let
definition should be defined separately and have proper names. And you have three there.
The more names the better. A good name is add-numbers
or take-out-the-trash
or fly-rockets
.
(defn decider
"Determine if the expected element found?"
[ [ a b c & rst]]
(and (= 1 a) (= 1 b) (= 0 c)))
(defn from-last-element
"Generate a new element from the last element of the existing list."
[lst upper]
(if (empty? lst)
[]
(let [ [ fst & rst] lst]
(if (>= fst upper)
(concat [0] (f rst upper))
(concat [(inc fst)] rst)))))
(defn pow
"Power of x to the nth"
[x n]
(reduce * (repeat n x)))
(defn calculate [a k decider]
(let [n (count a)
seed (for [i (range n)] 0)
total (pow n k)]
(if (or
(< k 1)
(> k n))
(throw (Exception. "IllegalArgument: k."))
(reduce (fn [a v]
(let [_last (last a)]
(if (decider _last)
(reduced a)
(conj a (from-last-element _last (dec n))))))
[seed] (range total)))))
(calculate ['a' 'b' 'c' 'd'] 3 (fn [[fst snd thd & rest]] (and (= fst 1)
(= snd 1)
(= thd 0))))
My challenge is that the code is not very straightforward, that it's hard to give them descriptive names.Why would one want to host his website on port 80 without SSL sertificate? I don't understand. Should it then 301 the user into the https version? Edit: Today I ran an app on aws and well... port 80. There is no certificate and anything. They didn't do it out of the box. Maybe it makes sense if I'd want to use CloudFront and then AWS would have unencrypted traffic inside but then it's still unencrypted in one network segment. So I'm puzzled why is it the default then...
What did you use to host the app? AWS is a collection of building blocks and some services that configure them
I currently making my certificate work. Found that I had to make the HTTP load balancer return a redirect to HTTPS. And I'll also create a cerfiticate.
> wget <http://_>._._/ -v
--2022-06-26 21:24:39-- <http://_/>
Resolving _ (_)... _, _
Connecting to _ (_)|_|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: <https://_:443/> [following]
--2022-06-26 21:24:39-- <https://_/>
Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt'
Connecting to _ (_)|_|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2211 (2.2K) [text/html]
Saving to: 'index.html'
index.html 100%[==========================================================================================================================================>] 2.16K --.-KB/s in 0s
2022-06-26 21:24:39 (33.5 MB/s) - 'index.html' saved [2211/2211]
So here we go. I manage to make a redirect. I didn't know that the LB could support the certificate :thinking_face:If you are hosting on a single instance you can use something like nginx and let's encrypt for your certificate
Currently I start with one instance that does too much stuff and then I'll probably need to split it into several instance types. So I don't want to commit yet.
What if it's a static HTML page? If it's simple and doesn't send or receive data, who cares?
But even if it's HTML page that you can interact with and that doesn't submit data to your backend... it could be a smart-contract page and then it's better to serve it through HTTPS :thinking_face: And then if it's your portfolio page then it's not nice if you get warnings from browser :thinking_face:
HTTPS makes sense even for web 1.0 HTML pages. I'm 90% certain that there have been cases of internet providers incorporating ads into plain HTTP HTML pages - exactly because HTTP does not prevent any MitM attacks.
If you configure your browser to run that page without JS they still can include static HTML but then the scripts won't run. But then they can even show "enable JS for full functionality" instead of the original so that you would enable the JS for them. Which would mean they could run the scripts anyway.
No need for JS at all. Just inject a bunch of <p>Your PC is infected, <a href="...">CLICK HERE</a> to fix it</p>
.
If you want to do this then why not return a 302 redirect instead of the content of the HTML... Way simpler.