Fork me on GitHub
#off-topic
<
2022-06-26
>
yubrshen05:06:08

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]]``

Martynas MaciuleviÄius05:06:19

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.

yubrshen16:06:43

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)] ``

Martynas MaciuleviÄius17:06:13

I suggest to split it into two or three different functions :thinking_face:

yubrshen22:06:39

You meant take out the inline lambda function as separate ones outside of the function calculate?

mauricio.szabo01:06:40

@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?

Martynas MaciuleviÄius04:06:35

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.

yubrshen03:06:35

Thanks! I'll try to give them names and move them outside to make it more readable.

Martynas MaciuleviÄius03:06:15

The more names the better. A good name is `add-numbers` or `take-out-the-trash` or `fly-rockets`.

š 1
yubrshen03:06:00

``````(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.

Martynas MaciuleviÄius16:06:44

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...

š 1
Dimitar Uzunov17:06:17

What did you use to host the app? AWS is a collection of building blocks and some services that configure them

Martynas MaciuleviÄius18:06:30

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.

Martynas MaciuleviÄius18:06:39

``````> 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://_/>
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:

Dimitar Uzunov18:06:11

If you are hosting on a single instance you can use something like nginx and let's encrypt for your certificate

Martynas MaciuleviÄius18:06:08

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.

š 1
Ben Sless19:06:27

What if it's a static HTML page? If it's simple and doesn't send or receive data, who cares?

1
Martynas MaciuleviÄius20:06:32

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:

p-himik20:06:10

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.

š 1
š¬ 1
Ben Sless03:06:21

That sounds... Terrifying

lsenjov04:06:34

Only a little MitM attack, as a treat

Ben Sless05:06:17

Is it possible if the website has no js?

lsenjov05:06:17

Yes, because it's modifying the bare HTML

lsenjov05:06:38

So it's fairly trivial if you've got the MitM to inject `<script>` tags

Martynas MaciuleviÄius05:06:51

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.

p-himik06:06:45

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>`.

lsenjov06:06:06

Or better, change the entire page to be an invisible `<a>` tag