Compare commits

..

6 Commits

Author SHA1 Message Date
9da584ded4 Make page lists bold
Some checks failed
continuous-integration/drone/push Build is failing
2020-05-04 03:36:23 -07:00
9452c90cf3 Switch back to Raleway 2020-05-04 03:35:24 -07:00
a80064f40a Merge branch 'master' of https://dev.danilafe.com/Web-Projects/blog-static 2020-05-04 03:29:48 -07:00
49691803cc Stop displaying links as inline-block 2020-05-04 03:28:17 -07:00
ee4738b245 Add redesign CSS 2020-05-04 03:23:55 -07:00
b270fa78da Add draft of lazy evaluation post 2020-05-04 01:58:25 -07:00
10 changed files with 143 additions and 25 deletions

View File

@ -0,0 +1,95 @@
---
title: "Clairvoyance for Good: Using Lazy Evaluation in Haskell"
date: 2020-05-03T20:05:29-07:00
tags: ["Haskell"]
draft: true
---
While tackling a project for work, I ran across a rather unpleasant problem.
I don't think it's valuable to go into the specifics here (it's rather
large and convoluted); however, the outcome of this experience led me to
discover a very interesting technique for lazy functional languages,
and I want to share what I learned.
### Time Traveling
Some time ago, I read [this post](https://kcsongor.github.io/time-travel-in-haskell-for-dummies/) by Csongor Kiss about time traveling in Haskell. It's
really cool, and makes a lot of sense if you have wrapped your head around
lazy evaluation. I'm going to present my take on it here, but please check out
Csongor's original post if you are interested.
Say that you have a list of integers, like `[3,2,6]`. Next, suppose that
you want to find the maximum value in the list. You can implement such
behavior quite simply with pattern matching:
```Haskell
myMax :: [Int] -> Int
myMax [] = error "Being total sucks"
myMax (x:xs) = max x $ myMax xs
```
You could even get fancy with a `fold`:
```Haskell
myMax :: [Int] -> Int
myMax = foldr1 max
```
All is well, and this is rather elementary Haskell. But now let's look at
something that Csongor calls the `repMax` problem:
> Imagine you had a list, and you wanted to replace all the elements of the
> list with the largest element, by only passing the list once.
How can we possibly do this in one pass? First, we need to find the maximum
element, and only then can we have something to replace the other numbers
with! It turns out, though, that we can just expect to have the future
value, and all will be well. Csongor provides the following example:
```Haskell {linenos=table}
repMax :: [Int] -> Int -> (Int, [Int])
repMax [] rep = (rep, [])
repMax [x] rep = (x, [rep])
repMax (l : ls) rep = (m', rep : ls')
where (m, ls') = repMax ls rep
m' = max m l
doRepMax :: [Int] -> [Int]
doRepMax xs = xs'
where (largest, xs') = repMax xs largest
```
In the above snippet, `repMax` expects to receive the maximum value of
its input list. At the same time, it also computes that maximum value,
returning it and the newly created list. `doRepMax` is where the magic happens:
the `where` clauses receives the maximum number from `repMax`, while at the
same time using that maximum number to call `repMax`!
This works because Haskell's evaluation model is, effectively,
[lazy graph reduction](https://en.wikipedia.org/wiki/Graph_reduction). That is,
you can think of Haskell as manipulating your code as
{{< sidenote "right" "tree-note" "a syntax tree," >}}
Why is it called graph reduction, you may be wondering, if the runtime is
manipulating syntax trees? To save on work, if a program refers to the
same value twice, Haskell has both of those references point to the
exact same graph. This violates the tree's property of having only one path
from the root to any node, and makes our program a graph. Graphs that
refer to themselves also violate the properties of a tree.
{{< /sidenote >}} performing
substitutions and simplifications as necessary until it reaches a final answer.
What the lazy part means is that parts of the syntax tree that are not yet
needed to compute the final answer can exist, unsimplied, in the tree. This is
what allows us to write the code above: the graph of `repMax xs largest`
effectively refers to itself. While traversing the list, it places references
to itself in place of each of the elements, and thanks to laziness, these
references are not evaluated.
Let's try a more complicated example. How about instead of creating a new list,
we return a `Map` containing the number of times each number occured, but only
when those numbers were a factor of the maximum numbers. Our expected output
will be:
```
>>> countMaxFactors [1,3,3,9]
fromList [(1, 1), (3, 2), (9, 1)]
```

View File

@ -40,7 +40,7 @@ $sidenote-highlight-border-width: .2rem;
} }
.sidenote-label { .sidenote-label {
border-bottom: .2rem solid $primary-color; border-bottom: .2rem dashed $primary-color;
} }
.sidenote-checkbox { .sidenote-checkbox {

View File

@ -14,10 +14,10 @@ h1, h2, h3, h4, h5, h6 {
margin-top: .5rem; margin-top: .5rem;
font-family: $font-heading; font-family: $font-heading;
font-weight: normal; font-weight: normal;
text-align: left; text-align: center;
a { a {
color: black; border-bottom: none;
&:hover { &:hover {
color: $primary-color; color: $primary-color;
@ -37,6 +37,10 @@ pre code {
background-color: $code-color; background-color: $code-color;
} }
div.highlight table pre {
margin: 0;
}
.container { .container {
position: relative; position: relative;
margin: auto; margin: auto;
@ -69,28 +73,33 @@ pre code {
} }
nav { nav {
background-color: $primary-color;
width: 100%; width: 100%;
margin: 1rem 0rem 1rem 0rem; margin: 0rem 0rem 1rem 0rem;
.container {
display: flex;
justify-content: center;
flex-wrap: wrap;
} }
nav a { a {
padding: .75em; padding: 0.25rem 0.75rem 0.25rem .75rem;
text-decoration: none; text-decoration: none;
color: white; color: black;
display: inline-block; display: inline-block;
border-bottom: none;
transition: color .25s, background-color .25s; transition: color .25s;
white-space: nowrap;
&:hover { &:hover {
color: $primary-color; color: $primary-color;
background-color: white;
} }
}
} }
.post-subscript { .post-subscript {
color: #8f8f8f; color: #8f8f8f;
text-align: center;
} }
.post-content { .post-content {
@ -122,8 +131,9 @@ h6 {
} }
a { a {
color: $primary-color-dark; color: black;
text-decoration: none; text-decoration: none;
border-bottom: .2rem solid $primary-color;
} }
img { img {
@ -154,6 +164,18 @@ td {
padding: 0.5rem; padding: 0.5rem;
} }
hr.header-divider {
background-color: $primary-color;
height: 0.3rem;
border: none;
border-radius: 0.15rem;
}
ul.page-list a {
border-bottom: none;
font-weight: 700;
}
.katex-html { .katex-html {
white-space: nowrap; white-space: nowrap;
} }

View File

@ -3,6 +3,7 @@
{{- partial "head.html" . -}} {{- partial "head.html" . -}}
<body> <body>
{{- partial "header.html" . -}} {{- partial "header.html" . -}}
<div class="container"><hr class="header-divider"></div>
<main class="container"> <main class="container">
{{- block "main" . }}{{- end }} {{- block "main" . }}{{- end }}
</main> </main>

View File

@ -1,7 +1,7 @@
{{ define "main" }} {{ define "main" }}
<h2>{{ .Title }}</h2> <h2>{{ .Title }}</h2>
<ul> <ul class="page-list">
{{ range .Pages.ByDate.Reverse }} {{ range .Pages.ByDate.Reverse }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li> <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }} {{ end }}

View File

@ -1,12 +1,12 @@
{{ define "main" }} {{ define "main" }}
<h2>{{ .Title }}</h2> <h2>{{ .Title }}</h2>
<div class="post-subscript"> <div class="post-subscript">
<p>Posted on {{ .Date.Format "January 2, 2006" }}.</p> <p>
<p>Tags:
{{ range .Params.tags }} {{ range .Params.tags }}
<a class="button" href="{{ $.Site.BaseURL }}/tags/{{ . | urlize }}">{{ . }}</a> <a class="button" href="{{ $.Site.BaseURL }}/tags/{{ . | urlize }}">{{ . }}</a>
{{ end }} {{ end }}
</p> </p>
<p>Posted on {{ .Date.Format "January 2, 2006" }}.</p>
</div> </div>
<div class="post-content"> <div class="post-content">

View File

@ -2,7 +2,7 @@
{{ .Content }} {{ .Content }}
Recent posts: Recent posts:
<ul> <ul class="page-list">
{{ range first 10 (where (where .Site.Pages.ByDate.Reverse "Section" "blog") ".Kind" "!=" "section") }} {{ range first 10 (where (where .Site.Pages.ByDate.Reverse "Section" "blog") ".Kind" "!=" "section") }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li> <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }} {{ end }}

View File

@ -3,7 +3,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#1dc868" /> <meta name="theme-color" content="#1dc868" />
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Lora|Raleway" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inconsolata&family=Raleway&family=Lora&display=swap" rel="stylesheet">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
{{ $style := resources.Get "scss/style.scss" | resources.ToCSS | resources.Minify }} {{ $style := resources.Get "scss/style.scss" | resources.ToCSS | resources.Minify }}
{{ $sidenotes := resources.Get "scss/sidenotes.scss" | resources.ToCSS | resources.Minify }} {{ $sidenotes := resources.Get "scss/sidenotes.scss" | resources.ToCSS | resources.Minify }}

View File

@ -1,7 +1,7 @@
{{ define "main" }} {{ define "main" }}
<h2>Tagged "{{ .Title }}"</h2> <h2>Tagged "{{ .Title }}"</h2>
<ul> <ul class="page-list">
{{ range .Pages.ByDate.Reverse }} {{ range .Pages.ByDate.Reverse }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li> <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }} {{ end }}

View File

@ -2,7 +2,7 @@
<h2>{{ .Title }}</h2> <h2>{{ .Title }}</h2>
Below is a list of all the tags ever used on this site. Below is a list of all the tags ever used on this site.
<ul> <ul class="page-list">
{{ range sort .Pages "Title" }} {{ range sort .Pages "Title" }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li> <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }} {{ end }}