2366 lines
342 KiB
XML
2366 lines
342 KiB
XML
|
<?xml version="1.0" encoding="UTF-8"?>
|
|||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|||
|
<channel>
|
|||
|
<title>mahdi</title>
|
|||
|
<description>a rabbit hole</description>
|
|||
|
<link>http://localhost:4000/</link>
|
|||
|
<atom:link href="http://localhost:4000/feed.xml" rel="self" type="application/rss+xml"/>
|
|||
|
<pubDate>Wed, 06 Jul 2022 17:36:29 +0100</pubDate>
|
|||
|
<lastBuildDate>Wed, 06 Jul 2022 17:36:29 +0100</lastBuildDate>
|
|||
|
<generator>Jekyll v4.2.2</generator>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>What is `Box<str>` and how is it different from `String` in Rust?</title>
|
|||
|
<description><p>Today I and a friend went down a rabbit hole about Rust and how it manages the heap when we use <code class="language-plaintext highlighter-rouge">Box</code>, or <code class="language-plaintext highlighter-rouge">String</code>, or <code class="language-plaintext highlighter-rouge">Vec</code>, and while we were at it, I found out there is such a thing as <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code>, which might look a bit <em>strange</em> to an untrained eye, since most of the time the <code class="language-plaintext highlighter-rouge">str</code> primitive type is passed around as <code class="language-plaintext highlighter-rouge">&amp;str</code>.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>TL;DR:</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> is a primitive <code class="language-plaintext highlighter-rouge">str</code> allocated on the heap, whereas <code class="language-plaintext highlighter-rouge">String</code> is actually a <code class="language-plaintext highlighter-rouge">Vec&lt;u8&gt;</code>, also allocated on the heap, which allows for efficient removals and appends. <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> (16 bytes) uses less memory than <code class="language-plaintext highlighter-rouge">String</code> (24 bytes).</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>I will be using <code class="language-plaintext highlighter-rouge">rust-lldb</code> throughout this post to understand what is going on in the rust programs we write and run. The source code for this blog post is available on <a href="https://git.mahdi.blog/mahdi/rust-memory-playground">mdibaiee/rust-memory-playground</a>.</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://git.mahdi.blog/mahdi/rust-memory-playground
|
|||
|
<span class="nb">cd </span>rust-memory-playground
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h1 id="the-stack">The Stack</h1>
|
|||
|
|
|||
|
<p>Most of the primitive data types used throughout a program, and the information about the program itself are usually allocated on the stack. Consider this simple program:</p>
|
|||
|
|
|||
|
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">add_ten</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u8</span> <span class="p">{</span>
|
|||
|
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
|
|||
|
<span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
|
|||
|
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="nf">add_ten</span><span class="p">(</span><span class="mi">9</span><span class="p">));</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Let’s examine the stack when we are running <code class="language-plaintext highlighter-rouge">a + b</code> by setting a breakpoint on that line:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo build &amp;&amp; rust-lldb target/debug/stack-program
|
|||
|
|
|||
|
(lldb) breakpoint set -f main.rs -l 3
|
|||
|
Breakpoint 1: where = stack-program`stack_program::add_ten::h42edbf0bdcb04851 + 24 at main.rs:3:5, address = 0x0000000100001354
|
|||
|
|
|||
|
(lldb) run
|
|||
|
Process 65188 launched: '/Users/mahdi/workshop/rust-memory-playground/target/debug/stack-program' (arm64)
|
|||
|
Process 65188 stopped
|
|||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|||
|
frame #0: 0x0000000100001354 stack-program`stack_program::add_ten::h42edbf0bdcb04851(a=5) at main.rs:3:5
|
|||
|
1 fn add_ten(a: u8) -&gt; u8 {
|
|||
|
2 let b = 10;
|
|||
|
-&gt; 3 a + b
|
|||
|
4 }
|
|||
|
5
|
|||
|
6
|
|||
|
7 fn main() {
|
|||
|
|
|||
|
(lldb) frame var -L -f X
|
|||
|
0x000000016fdfed7e: (unsigned char) a = 0x09
|
|||
|
0x000000016fdfed7f: (unsigned char) b = 0x0A
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Our program allocates two variables on the stack directly here. Notice that they are allocated right next to each other, their address only one bit apart. Most primitive types are allocated on the stack, and are copied when being passed around because they are small enough, so that copying them around is more reasonable than allocating them in the heap and passing around a pointer to them. In this case, <code class="language-plaintext highlighter-rouge">u8</code> can be allocated in a single byte, it would not make sense for us to allocate a pointer (which can vary in size, but are usually larger than 8 bytes). Every time you call a function, a copy of the values passed to it, along with the values defined in the function itself constitute the stack of that function.</p>
|
|||
|
|
|||
|
<p>The stack of a whole program includes more information though, such as the <em>backtrace</em>, which allows the program to know how to navigate: once I am done with this function, where should I return to? that information is available in the stack as well. Note the first couple of lines here, indicating that we are currently in <code class="language-plaintext highlighter-rouge">stack_program::add_then</code>, and we came here from <code class="language-plaintext highlighter-rouge">stack_program::main</code>, and so once we are finished with <code class="language-plaintext highlighter-rouge">add_then</code>, we will go back to <code class="language-plaintext highlighter-rouge">main</code>:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) thread backtrace
|
|||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|||
|
* frame #0: 0x0000000100001350 stack-program`stack_program::add_ten::hf7dc9cccae290c37(a='\t') at main.rs:3:5
|
|||
|
frame #1: 0x00000001000013a8 stack-program`stack_program::main::he22b9cf577b52c34 at main.rs:8:20
|
|||
|
frame #2: 0x00000001000015a4 stack-program`core::ops::function::FnOnce::call_once::hd6bac0cd3fcb8c07((null)=(stack-program`stack_program::main::he22b9cf577b52c34 at main.rs:7), (null)=&lt;unavailable&gt;) at function.rs:227:5
|
|||
|
frame #3: 0x00000001000014c4 stack-program`std::sys_common::backtrace::__rust_begin_short_backtrace::hc4df46810f9a7139(f=(stack-program`stack_program::main::he22b9cf577b52c34 at main.rs:7)) at backtrace.rs:122:18
|
|||
|
frame #4: 0x0000000100001178 stack-program`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hbec5b809d627978a at rt.rs:145:18
|
|||
|
frame #5: 0x000000010001440c stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::h485d4c2966ec30a8 at function.rs:259:13 [opt]
|
|||
|
frame #6: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panicking::try::do_call::h375a887be0bea938 at panicking.rs:492:40 [opt]
|
|||
|
frame #7: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panicking::try::hecad40482ef3be15 at panicking.rs:456:19 [opt]
|
|||
|
frame #8: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panic::catch_unwind::haf1f664eb41a88eb at panic.rs:137:14 [opt]
|
|||
|
frame #9: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::h976eba434e9ff4cf at rt.rs:128:48 [opt]
|
|||
|
frame #10: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panicking::try::do_call::h8f2501ab92e340b0 at panicking.rs:492:40 [opt]
|
|||
|
frame #11: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panicking::try::hbeb9f8df83454d42 at panicking.rs:456:19 [opt]
|
|||
|
frame #12: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e [inlined] std::panic::catch_unwind::h0a9390b2202af6e9 at panic.rs:137:14 [opt]
|
|||
|
frame #13: 0x0000000100014400 stack-program`std::rt::lang_start_internal::hc453db0ee48af82e at rt.rs:128:20 [opt]
|
|||
|
frame #14: 0x0000000100001140 stack-program`std::rt::lang_start::h69bdd2191bba2dab(main=(stack-program`stack_program::main::he22b9cf577b52c34 at main.rs:7), argc=1, argv=0x000000016fdff168) at rt.rs:144:17
|
|||
|
frame #15: 0x0000000100001434 stack-program`main + 32
|
|||
|
frame #16: 0x00000001000750f4 dyld`start + 520
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h1 id="box-string-and-vec-pointers-to-heap">Box, String and Vec: Pointers to Heap</h1>
|
|||
|
|
|||
|
<p>There are times when we are working with data types large enough that we would really like to avoid copying them when we are passing them around. Let’s say you have just copied a file that is 1,000,000 bytes (1Mb) in size. In this case it is much more memory and compute efficient to have a pointer to this value (8 bytes) rather than copying all the 1,000,000 bytes.</p>
|
|||
|
|
|||
|
<p>This is where types such as <code class="language-plaintext highlighter-rouge">Box</code>, <code class="language-plaintext highlighter-rouge">String</code> and <code class="language-plaintext highlighter-rouge">Vec</code> come into play: these types allow you to allocate something on heap, which is a chunk of memory separate from the stack that you can allocate on, and later reference those values using a pointer available on the stack.</p>
|
|||
|
|
|||
|
<p>Let’s start with <code class="language-plaintext highlighter-rouge">Box</code>, the most generic one, which allows you to allocate some data on the heap, consider this example:</p>
|
|||
|
|
|||
|
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
|||
|
<span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">5_u8</span><span class="p">);</span>
|
|||
|
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">10_u8</span><span class="p">;</span>
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"{}, {}"</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>We again use <code class="language-plaintext highlighter-rouge">lldb</code> to check out what is happening:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo build &amp;&amp; rust-lldb target/debug/stack-and-heap-program
|
|||
|
|
|||
|
(lldb) breakpoint set -f main.rs -l 4
|
|||
|
Breakpoint 1: where = stack-and-heap-program`stack_and_heap_program::main::ha895783273646dc7 + 100 at main.rs:4:5, address = 0x0000000100005264
|
|||
|
|
|||
|
(lldb) run
|
|||
|
Process 67451 launched: '/Users/mahdi/workshop/rust-memory-playground/target/debug/stack-and-heap-program' (arm64)
|
|||
|
Process 67451 stopped
|
|||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|||
|
frame #0: 0x0000000100005264 stack-and-heap-program`stack_and_heap_program::main::ha895783273646dc7 at main.rs:4:5
|
|||
|
1 fn main() {
|
|||
|
2 let a = Box::new(5_u8);
|
|||
|
3 let b = 10_u8;
|
|||
|
-&gt; 4 println!("{}, {}", a, b);
|
|||
|
5 }
|
|||
|
|
|||
|
(lldb) frame var -L -f X
|
|||
|
0x000000016fdfed48: (unsigned char *) a = 0x0000600000008010 "\U00000005"
|
|||
|
0x000000016fdfed57: (unsigned char) b = 0x0A
|
|||
|
|
|||
|
(lldb) memory read -count 1 -f X 0x0000600000008010
|
|||
|
0x600000008010: 0x05
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Note that here, instead of <code class="language-plaintext highlighter-rouge">a</code> having the value <code class="language-plaintext highlighter-rouge">5</code>, has the value <code class="language-plaintext highlighter-rouge">0x0000600000008010</code>, which is a pointer to a location in memory! <code class="language-plaintext highlighter-rouge">lldb</code> is recognises that this is a pointer (note the <code class="language-plaintext highlighter-rouge">*</code> sign beside the variable type) and shows us what the memory location contains, but we can also directly read that memory location, and of course we find <code class="language-plaintext highlighter-rouge">5</code> there. The address of the heap-allocated <code class="language-plaintext highlighter-rouge">5</code> is far from the stack-allocated <code class="language-plaintext highlighter-rouge">10</code>, since stack and heap are separate parts of memory.</p>
|
|||
|
|
|||
|
<p>Using <code class="language-plaintext highlighter-rouge">Box</code> for an unsigned 8-bit value does not really make sense, the value itself is smaller than the pointer created by <code class="language-plaintext highlighter-rouge">Box</code>, however allocating on heap is useful when we have data that we need be able to pass around the program without copying it.</p>
|
|||
|
|
|||
|
<p>Turns out, <code class="language-plaintext highlighter-rouge">String</code> and <code class="language-plaintext highlighter-rouge">Vec</code> cover two of the most common cases where we may want to allocate something on heap! Let’s look at what goes on behind allocating a variable of type <code class="language-plaintext highlighter-rouge">String</code>:</p>
|
|||
|
|
|||
|
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
|||
|
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"hello"</span><span class="p">);</span>
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>And here we go again:</p>
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) breakpoint set -f main.rs -l 3
|
|||
|
Breakpoint 1: where = string-program`string_program::main::h64ca96ee87b0ceaf + 44 at main.rs:3:5, address = 0x000000010000476c
|
|||
|
|
|||
|
(lldb) run
|
|||
|
Process 68317 launched: '/Users/mahdi/workshop/rust-memory-playground/target/debug/string-program' (arm64)
|
|||
|
Process 68317 stopped
|
|||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|||
|
frame #0: 0x000000010000476c string-program`string_program::main::h64ca96ee87b0ceaf at main.rs:3:5
|
|||
|
1 fn main() {
|
|||
|
2 let s = String::from("hello");
|
|||
|
-&gt; 3 println!("{}", s);
|
|||
|
4 }
|
|||
|
|
|||
|
(lldb) frame var -L -T
|
|||
|
0x000000016fdfed78: (alloc::string::String) s = "hello" {
|
|||
|
0x000000016fdfed78: (alloc::vec::Vec&lt;unsigned char, alloc::alloc::Global&gt;) vec = size=5 {
|
|||
|
0x0000600000004010: (unsigned char) [0] = 'h'
|
|||
|
0x0000600000004011: (unsigned char) [1] = 'e'
|
|||
|
0x0000600000004012: (unsigned char) [2] = 'l'
|
|||
|
0x0000600000004013: (unsigned char) [3] = 'l'
|
|||
|
0x0000600000004014: (unsigned char) [4] = 'o'
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>This is a formatted output from <code class="language-plaintext highlighter-rouge">lldb</code>, and here you can see that the <code class="language-plaintext highlighter-rouge">String</code> type is basically a <code class="language-plaintext highlighter-rouge">Vec&lt;unsigned char, alloc::Global&gt;</code> (note that <code class="language-plaintext highlighter-rouge">unsigned char</code> is represented using <code class="language-plaintext highlighter-rouge">u8</code> in Rust, so in Rust terminology the type is <code class="language-plaintext highlighter-rouge">Vec&lt;u8&gt;</code>), let’s now look at the same command but this time raw and unformatted (<code class="language-plaintext highlighter-rouge">-R</code>):</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) frame var -L -T -R
|
|||
|
0x000000016fdfed78: (alloc::string::String) s = {
|
|||
|
0x000000016fdfed78: (alloc::vec::Vec&lt;unsigned char, alloc::alloc::Global&gt;) vec = {
|
|||
|
0x000000016fdfed78: (alloc::raw_vec::RawVec&lt;unsigned char, alloc::alloc::Global&gt;) buf = {
|
|||
|
0x000000016fdfed78: (core::ptr::unique::Unique&lt;unsigned char&gt;) ptr = {
|
|||
|
0x000000016fdfed78: (unsigned char *) pointer = 0x0000600000004010
|
|||
|
0x000000016fdfed78: (core::marker::PhantomData&lt;unsigned char&gt;) _marker = {}
|
|||
|
}
|
|||
|
0x000000016fdfed80: (unsigned long) cap = 6
|
|||
|
0x000000016fdfed78: (alloc::alloc::Global) alloc = {}
|
|||
|
}
|
|||
|
0x000000016fdfed88: (unsigned long) len = 6
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ah! I see the <code class="language-plaintext highlighter-rouge">ptr</code> field of <code class="language-plaintext highlighter-rouge">RawVec</code> with a value of <code class="language-plaintext highlighter-rouge">0x0000600000004010</code>, that is the memory address of the beginning of our string (namely the <code class="language-plaintext highlighter-rouge">h</code> of our <code class="language-plaintext highlighter-rouge">hello</code>)! There is also <code class="language-plaintext highlighter-rouge">cap</code> and <code class="language-plaintext highlighter-rouge">len</code>, which respectively stand for capacity and length, with the value 6, indicating that our string is of capacity and length 6; the difference between the two being that <a href="https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#capacity-and-reallocation">you can have a <code class="language-plaintext highlighter-rouge">Vec</code> with a capacity of 10 while it has zero items</a>, this would allow you to append 10 items to the <code class="language-plaintext highlighter-rouge">Vec</code> without having a new allocation for each append, making the process more efficient, and also a <a href="https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#guarantees">Vec is not automatically shrunk down</a> in size when items are removed from it to avoid unnecessary deallocations, hence the length might be smaller than the capacity. So in a nutshell, our String is basically something like this (inspired by <a href="https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#guarantees">std::vec::Vec</a>):</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Stack:
|
|||
|
--------------------------------
|
|||
|
| String |
|
|||
|
| \-&gt; Vec |
|
|||
|
| \-&gt; (ptr, cap, len) |
|
|||
|
| | |
|
|||
|
-----------------|--------------
|
|||
|
Heap: v
|
|||
|
-----------------------------
|
|||
|
| ('h', 'e', 'l', 'l', 'o') |
|
|||
|
-----------------------------
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Okay, so far so good. We have <code class="language-plaintext highlighter-rouge">String</code>, which uses a <code class="language-plaintext highlighter-rouge">Vec</code> under the hood, which is represented by a pointer, capacity and length triplet.</p>
|
|||
|
|
|||
|
<p>If <code class="language-plaintext highlighter-rouge">String</code> is already heap-allocated, why would anyone want <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code>!? Let’s look at how <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> would be represented in memory:</p>
|
|||
|
|
|||
|
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
|||
|
<span class="k">let</span> <span class="n">boxed_str</span><span class="p">:</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="nb">str</span><span class="o">&gt;</span> <span class="o">=</span> <span class="s">"hello"</span><span class="nf">.into</span><span class="p">();</span>
|
|||
|
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"boxed_str: {}"</span><span class="p">,</span> <span class="n">boxed_str</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>And <code class="language-plaintext highlighter-rouge">lldb</code> tells us:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x000000016fdfed80: (alloc::boxed::Box&lt;&gt;) boxed_str = {
|
|||
|
0x000000016fdfed80: data_ptr = 0x0000600000004010 "hello"
|
|||
|
0x000000016fdfed88: length = 5
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Okay, so a <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> is much simpler than a <code class="language-plaintext highlighter-rouge">String</code>: there is no <code class="language-plaintext highlighter-rouge">Vec</code>, and no <code class="language-plaintext highlighter-rouge">capacity</code>, and the underlying data is a primitive <code class="language-plaintext highlighter-rouge">str</code> that does not allow efficient appending or removing. It is a smaller representation as well, due to the missing <code class="language-plaintext highlighter-rouge">capacity</code> field, comparing their memory size on stack using <a href="https://doc.rust-lang.org/std/mem/fn.size_of_val.html">std::mem::size_of_val</a>:</p>
|
|||
|
|
|||
|
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">boxed_str</span><span class="p">:</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="nb">str</span><span class="o">&gt;</span> <span class="o">=</span> <span class="s">"hello"</span><span class="nf">.into</span><span class="p">();</span>
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"size of boxed_str on stack: {}"</span><span class="p">,</span> <span class="nn">std</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nf">size_of_val</span><span class="p">(</span><span class="o">&amp;</span><span class="n">boxed_str</span><span class="p">));</span>
|
|||
|
|
|||
|
<span class="k">let</span> <span class="n">s</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"hello"</span><span class="p">);</span>
|
|||
|
<span class="nd">println!</span><span class="p">(</span><span class="s">"size of string on stack: {}"</span><span class="p">,</span> <span class="nn">std</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nf">size_of_val</span><span class="p">(</span><span class="o">&amp;</span><span class="n">s</span><span class="p">));</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Results in:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size of boxed_str on stack: 16
|
|||
|
size of string on stack: 24
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Note that their size on heap is the same, because they are both storing the bytes for <code class="language-plaintext highlighter-rouge">hello</code> on the heap (the measurements below show all of the heap allocations of the program, and not only the string. What matters here is that these two programs have exact same heap size in total):</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cargo run --bin string-dhat
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
|
|||
|
Running `target/debug/string-dhat`
|
|||
|
hello
|
|||
|
dhat: Total: 1,029 bytes in 2 blocks
|
|||
|
dhat: At t-gmax: 1,029 bytes in 2 blocks
|
|||
|
dhat: At t-end: 1,024 bytes in 1 blocks
|
|||
|
dhat: The data has been saved to dhat-heap.json, and is viewable with dhat/dh_view.html
|
|||
|
|
|||
|
$ cargo run --bin box-str-dhat
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
|
|||
|
Running `target/debug/box-str-dhat`
|
|||
|
boxed_str: hello
|
|||
|
dhat: Total: 1,029 bytes in 2 blocks
|
|||
|
dhat: At t-gmax: 1,029 bytes in 2 blocks
|
|||
|
dhat: At t-end: 1,024 bytes in 1 blocks
|
|||
|
dhat: The data has been saved to dhat-heap.json, and is viewable with dhat/dh_view.html
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>There is also <code class="language-plaintext highlighter-rouge">Box&lt;[T]&gt;</code> which is the fixed size counterpart to <code class="language-plaintext highlighter-rouge">Vec&lt;T&gt;</code>.</p>
|
|||
|
|
|||
|
<h1 id="should-i-use-boxstr-or-string">Should I use <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> or <code class="language-plaintext highlighter-rouge">String</code>?</h1>
|
|||
|
|
|||
|
<p>The only use case for <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> over <code class="language-plaintext highlighter-rouge">String</code> that I can think of, is optimising for memory usage when the string is fixed and you do not intend to append or remove from it. I looked for examples of <code class="language-plaintext highlighter-rouge">Box&lt;str&gt;</code> being used, and I found a few examples:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Hyper uses it in a part to reduce memory usage, since the string they have is read-only: <a href="https://github.com/hyperium/hyper/pull/2727">hyper#2727</a></li>
|
|||
|
<li>Rust-analyzer uses it to store some strings in their snippets data structre: <a href="https://github.com/rust-lang/rust-analyzer/blob/5c88d9344c5b32988bfbfc090f50aba5de1db062/crates/ide-completion/src/snippet.rs#L123">rust-lang/rust-analyzer/crates/ide-completion/src/snippet.rs</a></li>
|
|||
|
<li>It is also used in some parts in the compiler itself, probably with the same aim of optimising memory usage: <a href="https://github.com/rust-lang/rust/blob/7846610470392abc3ab1470853bbe7b408fe4254/src/libsyntax/symbol.rs#L82-L85">rust-lang/rust/src/libsyntax/symbol.rs</a></li>
|
|||
|
</ul>
|
|||
|
</description>
|
|||
|
<pubDate>Thu, 16 Jun 2022 01:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/rust-box-str-vs-string/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/rust-box-str-vs-string/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>programming</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>On Inherent Subjectivity of Some Things</title>
|
|||
|
<description><p>As a computer scientist and someone who loves <a href="/mathematical-induction-proving-tiling-methods">mathematics</a> and <a href="/typoclassopedia-exercise-solutions">abstractions</a>, I was obsessed with the idea of rationality, that is, an <em>objective</em> and absolute rationality, however I ended up in a philosophy course that showed me the opposite.</p>
|
|||
|
|
|||
|
<p>I somehow stumbled upon Eliezer Yudkowsky’s <a href="https://www.readthesequences.com/">Rationality: From AI to Zombies</a> about 4 years ago, and it took me two years to go through it all but I was absolutely fascinated by this book. I <em>knew</em> how to be rational now, and I could <em>prove</em> it using mathematics, what else could I ask for!</p>
|
|||
|
|
|||
|
<p>The book basically looks at the world as a probabilistic system, and everything that happens can be assigned probabilities, and using mathematical theorems such as Bayes Theorem, we can predict outcomes of certain actions and then decide between them. There is a lot of focus on <a href="https://en.wikipedia.org/wiki/List_of_cognitive_biases">cognitive biases</a> as well. I was particularly very interested about these biases, and so I set out to learn more about them, and that’s how I found my current course: <a href="https://cogsci.ucd.ie">Cognitive Science at University College Dublin</a>.</p>
|
|||
|
|
|||
|
<p>So I enter this course with this mindset: we can objectively analyse the world around us using probability and statistics (mathematics), but we are limited by our cognitive biases, so I want to learn about these cognitive biases: where do they come from, how can they be resisted to allow us to act more rationally and so on. These questions would mainly fall under the umbrella of psychology…</p>
|
|||
|
|
|||
|
<p>However… I found myself to be more and more interested in the philosophy side of this course than the psychology side, hell I even started to not like the psychology side anymore, but fall in love with the philosophy. This is where I found the opposite of what I had come for: an alternative definition of objectivity, and an inherent subjectivity of some things. This is mainly inspired by Thomas Nagel’s What Is It Like To Be A Bat <a class="citation" href="#nagel1974like">(Nagel, 1974)</a>.</p>
|
|||
|
|
|||
|
<h2 id="what-is-objectivity-anyway">What is Objectivity Anyway?</h2>
|
|||
|
|
|||
|
<p>This is probably the main question here. What is objectivity? I don’t think dictionary definitions are particularly authoritative when it comes to philosophy discussions, but I found this dictionary definition interesting to open the topic with:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>the quality or character of being objective : lack of favoritism toward one side or another : freedom from bias. <a class="citation" href="#objectivity-merriam-webster">(Merriam-Webster, 2021)</a></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>This definition itself has ambiguous phrases such as “freedom from bias”, what does that mean? When can we say that we are free from bias? Let’s look at how bias is defined in the same dictionary:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>an inclination of temperament or outlook <a class="citation" href="#bias-merriam-webster">(Merriam-Webster, 2021)</a></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>But… is it really possible to have no inclination at all in our temperament and outlook? Let’s look at the definition of subjective, that will help us here:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>relating to the way a person experiences things in his or her own mind <a class="citation" href="#subjective-merriam-webster">(Merriam-Webster, 2021)</a></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Is it possible for us to have a view of something without it being part of our experience? It seems not. All that we do, all our views and expressions and our interactions are part of our experience as a person, and it relates to us on an intimate level, which means that everything that we do as individuals is subjective. In that sense, it seems impossible for any individual to be objective, since they will always have some form of inclination about everything.</p>
|
|||
|
|
|||
|
<p>What does this leave us with then when we ask what is objectivity? A better definition of objectivity in my opinion is one given by Thomas Nagel:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>It may be more accurate to think of objectivity as a direction in which the understanding can travel. […] The process of reduction is a move in the direction of greater objectivity, toward a more accurate view of the real nature of things. This is accomplished by reducing our dependence on individual or species-specific points of view toward the object of investigation. We describe it not in terms of the impressions it makes on our senses, but in terms of its more general effects and of properties detectable by means other than the human senses. <a class="citation" href="#nagel1974like">(Nagel, 1974)</a></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>In this sense, there is no black-and-white distinction between subjectivity and objectivity, but rather it is a spectrum, a line on which we can walk from subjectivity towards objectivity.</p>
|
|||
|
|
|||
|
<p><img src="/img/inherent-subjectivity/subjective-objective.png" alt="Subjective-Objective spectrum: On Subjective side we have Individual perception, in the middle Agreement with others, and on the Objective side Agreement with other apparatus" /></p>
|
|||
|
|
|||
|
<p>We start with our individual perceptions as the most objective view and description, we then move towards descriptions that allow us to agree with other (human) beings, and finally we move towards descriptions that can be verified and agreed upon by other apparatus, although it is important to understand that even the apparatus that we may use to describe things are not necessarily free from bias, since they are created by biased individuals and groups. By now you may notice that if a measuring device is made to be agreeable between a large group of people, it is already more objective than a device made by a single individual! However, absolute objectivity, which we may call “a view from nowhere” may not be attainable by us, because we will always be viewing things from our own perspectives, even if it is a large, collective perspective that we agree on, it is not a view from nowhere.</p>
|
|||
|
|
|||
|
<p><img src="/img/inherent-subjectivity/subjective-objective-example.png" alt="Subjective-Objective spectrum: A single person says a ball is 10cm radius, 1/4 objectivity. A group of people say it's 10cm radius, 1/2 objectivity. A group of people with a ruler say it's 10cm radius, 3/4 objectivity" /></p>
|
|||
|
|
|||
|
<h2 id="inherently-subjective-things">Inherently Subjective Things</h2>
|
|||
|
|
|||
|
<p>With our definition of objectivity in place, now let’s see: is there something that we cannot move towards objectivity about? Yes. That is our personal experiences.</p>
|
|||
|
|
|||
|
<p>See, if there is an attempt to give a more objective description of <em>my</em> personal experience, there will need to be either an agreement among a group of beings about this description of my personal experience, or there should be an apparatus that we can agree on that measures my personal experience. However, my personal experience is personal exactly because it is completely dependent and originated from my perspective alone, and no one else’s; and as soon as you try to move towards objectivity by trying to describe this experience in a way that moves away from my person-specific and species-specific standpoint, towards a more agreeable and general description that even non-human beings or apparatus can agree with, you lose the initial personal experience in the process, so you end up with a non-personal description of the experience which misses the point of the actual subjective experience I have.</p>
|
|||
|
|
|||
|
<p>So, you can come up with <em>some</em> description of my experience, but you can’t actually describe the subjective experience of being me as it really is. The walk towards objectivity requires you to drop the subjectivity of my experience, and hence, some inherently subjective things such as our personal experiences can’t be objectified.</p>
|
|||
|
|
|||
|
<p>This is how Nagel puts it (I think this may be a bit hard to read without reading the whole paper):</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Experience itself, however, does not seem to fit the pattern. The idea of moving from appearance to reality seems to make no sense here. What is the analogue in this case to pursuing a more objective understanding of the same phenomena by abandoning the initial subjective viewpoint toward them in favor of another that is more objective but concerns the same thing? Certainly it appears unlikely that we will get closer to the real nature of human experience by leaving behind the particularity of our human point of view and striving for a description in terms accessible to beings that could not imagine what it was like to be us. If the subjective character of experience is fully comprehensible only from one point of view, then any shift to greater objectivity that is, less attachment to a specific viewpoint does not take us nearer to the real nature of the phenomenon: it takes us farther away from it. <a class="citation" href="#nagel1974like">(Nagel, 1974)</a></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h2 id="so-what-or-why-is-this-important">So What? (Or: Why is This Important?)</h2>
|
|||
|
|
|||
|
<p>This realisation means that objectifying people’s subjective experiences is not possible, we will never be able to decipher someone’s subjective experience of something. This does not mean we should not try to <em>understand</em> people, rather, it means we should always consider that our understanding of someone’s subjective experience will never be objective, it will always be merely our perspective of it. When it comes to people’s personal experiences, we can’t be sure that we are right, the way we are confident we are right after measuring a distance using our agreed-upon metric ruler; when it comes to subjective experiences it’s always only a crude approximation. “In the end one experiences only oneself.” <a class="citation" href="#nietzsche2008thus">(Nietzsche, 2008)</a></p>
|
|||
|
|
|||
|
<p>This video was sent to me by a friend today, and it is great timing, because it is very relevant:</p>
|
|||
|
|
|||
|
<iframe class="centered" width="560" height="315" src="https://www.youtube-nocookie.com/embed/oRG2jlQWCsY" title="Good Will Hunting | 'Your Move Chief' (HD) - Matt Damon, Robin Williams | MIRAMAX" frameborder="0" allow="picture-in-picture" allowfullscreen=""></iframe>
|
|||
|
|
|||
|
<!--https://postcognitivism.wordpress.com/2021/04/06/the-great-escape-can-we-transcend-our-own-conceptual-frameworks/
|
|||
|
https://gatelessgateblog.wordpress.com/
|
|||
|
https://www.sciencedirect.com/science/article/pii/S0388000121000802
|
|||
|
Distinctions and Common Ground in Collective Epistemology-->
|
|||
|
|
|||
|
<h2 id="references">References</h2>
|
|||
|
|
|||
|
<ol class="bibliography"><li><span id="nagel1974like">Nagel, T. (1974). What is it like to be a bat. <i>Readings in Philosophy of Psychology</i>, <i>1</i>, 159–168.</span></li>
|
|||
|
<li><span id="objectivity-merriam-webster">Merriam-Webster. (2021). <i>Objectivity. In Merriam-Webster.com dictionary.</i> https://www.merriam-webster.com/dictionary/objectivity</span></li>
|
|||
|
<li><span id="bias-merriam-webster">Merriam-Webster. (2021). <i>Bias. In Merriam-Webster.com dictionary.</i> https://www.merriam-webster.com/dictionary/bias</span></li>
|
|||
|
<li><span id="subjective-merriam-webster">Merriam-Webster. (2021). <i>Subjective. In Merriam-Webster.com dictionary.</i> https://www.merriam-webster.com/dictionary/subjective</span></li>
|
|||
|
<li><span id="nietzsche2008thus">Nietzsche, F. (2008). <i>Thus spoke Zarathustra: A book for everyone and nobody</i>. Oxford University Press.</span></li></ol>
|
|||
|
</description>
|
|||
|
<pubDate>Sat, 30 Oct 2021 13:57:46 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/alternative-objectivity-and-inherent-subjectivity/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/alternative-objectivity-and-inherent-subjectivity/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>philosophy</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Iran Sanctions: A Story of Discrimination and Isolation</title>
|
|||
|
<description><p>Let me take you through a story on what it feels like to be isolated from the world, not by choice, but rather, by force. This is a story of discrimination, of monopoly, of people shrugging to these issues and of utterances that affect lives of millions.</p>
|
|||
|
|
|||
|
<p>Living in Iran, or any sanctioned country for that matter, you learn to read “anyone, anywhere” with an appendix of “except you”. You soon learn “worldwide shipping” excludes you, that’s when you start wondering, are you not living in “the world”? Where is this “world” they talk about?</p>
|
|||
|
|
|||
|
<p>Here is an example of a beautiful, hopeful message from Khan Academy:</p>
|
|||
|
|
|||
|
<p><img src="/img/discrimination/khan-academy.png" alt="Khan Academy's Landing Page: We’re a nonprofit with the mission to provide a free, world-class education for anyone, anywhere." /></p>
|
|||
|
|
|||
|
<p><span class="image-caption">“We’re a nonprofit with the mission to provide a free, world-class education for anyone, anywhere.”</span></p>
|
|||
|
|
|||
|
<p>No one probably realizes that this is not true, but yes, Khan Academy is not available to Iranians, Cubans, Syrians, people of Crimea, and some others. That’s because <a href="https://cloud.google.com/customers/khan-academy/">they run on Google Cloud</a>, an infrastructure provider that completely blocks all sanctioned countries from accessing any application hosted on it. Who else hosts their service there? Take a look at <a href="https://cloud.google.com/customers/">342 notable customers</a> of Google Cloud, but remember, there are thousands more customers of Google Cloud and similar American infrastructure providers.</p>
|
|||
|
|
|||
|
<p>But the story doesn’t end here, of course. Let’s go through the effects of sanctions on everyday lives of people, who have nothing to do with the politics of the country they are living in, and who are being discriminated only because they were born in geographical coordinates that lie in a certain boundary defined by people they don’t even know.</p>
|
|||
|
|
|||
|
<h1 id="the-internet">The Internet</h1>
|
|||
|
|
|||
|
<p>The internet, the tool of the global society for communicating across the planet, <em>the</em> tool for sharing knowledge with the human population across the world.</p>
|
|||
|
|
|||
|
<p>As if the Iranian government’s blockage and censorship of the internet wasn’t enough, we now have to deal with external sanctions blocking our access as well. Here’s a gallery of blocked access messages we see on a daily basis:</p>
|
|||
|
|
|||
|
<p><img src="/img/discrimination/403-forbidden-iran-sanctions.jpg" alt="Various websites and their respective webpages seen only by sanctioned countries" />
|
|||
|
<span class="image-caption">Various websites and their respective webpages seen only by sanctioned countries</span></p>
|
|||
|
|
|||
|
<p>These websites include GitHub, Slack, Kaggle, Docker, GitLab, Amazon AWS, Twitter, Bluemix, Khan Academy and more. Here is a longer, developer-oriented (but definitely not exhaustive) list of hosts blocking our access: <a href="https://raw.githubusercontent.com/freedomofdevelopers/fod/master/domains">freedomofdevelopers/domains</a>.</p>
|
|||
|
|
|||
|
<p>The websites that blocked our access mostly did it without prior notice, they just disabled our accounts, took our data from us, and did not let us even backup or export our data afterwards, in other words, lost messages, lost files and credentials.</p>
|
|||
|
|
|||
|
<p>This, in part, is caused by the global monopoly of American companies such as Google, Amazon, GitHub and alike in their respective fields. This means if The United States decides to pressure a specific target, the target population is likely to be left without much of an alternative or option, since a great proportion of the land is covered by American companies.</p>
|
|||
|
|
|||
|
<p>Iranian users rely heavily on use of VPN services and proxy servers to bypass censorship, but now with most Cloud Providers blocking access of Iranians, we are left with limited, usually more expensive options for setting up these servers.</p>
|
|||
|
|
|||
|
<p>This is a clear discrimination based on nationality and a breach of <a href="https://en.wikipedia.org/wiki/Internet_freedom">Internet Freedom</a>. These websites do not block us because we acted in a wrong way, or even, at cases, because we live in Iran, but because we were <em>born</em> in Iran. Now, you may say this is because of the law and they have no choice. That’s true in some cases, though most of the time the implementation of these laws seem to go further than what the laws actually require. The companies seem to go the <em>easy</em> way by blocking access as much as they can to avoid holes in their system.</p>
|
|||
|
|
|||
|
<h1 id="drugs-medicine-and-medical-devices">Drugs, Medicine, and Medical Devices</h1>
|
|||
|
|
|||
|
<p>There are various sources and articles on how the U.S. sanctions have affected Iranian patients by limiting exports of drugs, medical devices or by indirectly disrupting the pharmaceutical industry by cutting exports of raw material used by these companies to produce medical drugs. Almost every person living in Iran can consciously feel the shortage of drugs and their growing price, but I will refer to an article on NCBI as a proof.</p>
|
|||
|
|
|||
|
<p>Quoting from <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4897941/">NCBI: Addressing the impact of economic sanctions on Iranian drug shortages in the joint comprehensive plan of action: promoting access to medicines and health diplomacy</a>:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
Although the revised and current Iranian sanctions regime does not specifically prohibit the export of humanitarian goods and pharmaceuticals, many of the administrative and regulatory processes have made it difficult to export life-saving medicines to Iran. This includes the need to navigate a complex export control regulatory process, the inability of Iranian banks to do business with the international banking system and U.S. corporations, currency shortages, and the inability to secure terms of shipping, insurance and other services needed to facilitate medicines trade [4]. As a result, millions of Iranians that suffer from life-threatening diseases have experienced “exorbitant prices”, stock outs of medicines, and are often forced to purchase drugs from the black market.
|
|||
|
|
|||
|
[...]
|
|||
|
|
|||
|
Severe medication shortages in Iran are diverse and span several therapeutic classes and disease states. This includes drug shortages for other critical areas of healthcare delivery, including organ transplant drugs, and even vaccine shortages.
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>And on the topic of weakening of the pharmaceutical companies:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
Inaccessibility of vital medications and their raw ingredients combined with Iran’s weakening domestic pharmaceutical industry has also resulted in an influx of counterfeit, fraudulent, and substandard medicines into Iran’s health care system. An unregulated black market has developed as a byproduct of drug shortages, introducing medications whose origins and authenticity are often unknown, and has led to expired medications’ distribution and sale, even at potentially very high prices [8]. Hence, the global counterfeit medicines trade, recognized as a serious public health concern, is one that is currently being enabled as a consequence of drug shortages and ongoing Iranian economic sanctions
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Foreign Policy also writes <a href="https://foreignpolicy.com/2019/08/14/u-s-sanctions-are-killing-cancer-patients-in-iran/">U.S. Sanctions Are Killing Cancer Patients in Iran</a>:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Washington claims that maximum pressure won’t stop the supply of medicine and other humanitarian necessities, but banking sanctions are driving up import prices, blocking supply chains, and creating deadly drug shortages.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Although U.S. sanctions are engineered in a way that may appear not to target humanitarian access to food and medicine, in practice U.S. sanctions function as a tool of economic war.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p><a href="https://www.who.int/mediacentre/news/statements/fundamental-human-right/en/">Health is a fundamental human right</a>, but the embargo clearly goes against giving people access to life-saving medicine. It brings tears to my eyes to think about people losing a loved one over inability to access a drug or medical device that’s no longer available in Iran.</p>
|
|||
|
|
|||
|
<h1 id="currency-fluctuations-an-unpredictable-life">Currency Fluctuations: An Unpredictable Life</h1>
|
|||
|
|
|||
|
<p>I’m pretty sure most of the people reading this blog post, unless they are Iranians, will not find this section familiar. It’s [fortunately] not a common experience across the planet, but let me tell you about living a life of zero predictability.</p>
|
|||
|
|
|||
|
<p>Imagine this: You sell your car today, and you start a hunt for a new car to buy as a replacement. For the sake of the example, you are looking for a second-hand car.
|
|||
|
I will use a dummy currency unit here to simplify the example. You sold your car for 1000 units, and during the week you are looking for a new car, you start to see the car you just sold and every other car on the market, is gaining price exponentially. After a week, the same car that you sold is priced at 1800 units of currency and it’s growing. It’s like putting a car on neutral in a downward slope and seeing it go up the hill! Now you are left with 1000 units of currency, and you are only able to buy the same car if you put in your extra 800 savings, otherwise you are going to ride a car with significantly less quality or no car at all. More on <a href="https://www.reuters.com/article/us-iran-economy-imf-idUSKCN1S509Q">Iran’s inflation</a> as a result of tighter sanctions.</p>
|
|||
|
|
|||
|
<p>I am pretty sure no matter how much I try to help you visualize this, you can not comprehend what it means to live in such a situation. I always use the metaphor of being a circus actor trying to balance on a moving cylinder to describe what it means to survive the fluctuations of our currency, which in turn affects all your expenses, but not your income.</p>
|
|||
|
|
|||
|
<p><img src="/img/discrimination/act04-1.jpg" alt="Circus actor balancing on cylinders" /></p>
|
|||
|
|
|||
|
<p>This is also an effect of the sanctions on the economy that we people feel with our every inch and are pressured by. This in turn causes a <a href="#a-weak-economys-rippling-effect">rippling effect</a> on every other part of the society. Quoting <a href="https://www.thenational.ae/business/economy/explainer-the-collapse-of-the-iranian-rial-1.754707">Explainer: the collapse of the Iranian rial</a></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
Has the US decision made things worse?
|
|||
|
|
|||
|
Yes. Mr Trump’s decision to exit the US-Iran nuclear agreement signed in 2015 has dented Iran’s economic outlook and set in motion a cascade of damaging effects. It has deterred global companies from doing business with Iran, leading to a liquidity crunch and a lack of foreign exchange in the country. US measures also put pressure on a banking system already strained by the previous sanctions regime before the adoption of the JCPOA in January 2016.
|
|||
|
|
|||
|
A re-imposition of sanctions is expected to cause a drop in Iranian oil exports, with severe repercussions. Iran is home to the world’s largest reserves of gas and is the Middle East’s third-largest oil producer. In May, BMI downgraded its GDP growth forecast for Iran to 3.1 per cent in 2018 and 0.8 per cent in 2019, from 4.3 per cent and 4.5 per cent previously.
|
|||
|
|
|||
|
“Iran is likely to experience depreciatory pressures on the rial and rising inflation as a result of lower foreign currency inflows that will constrain domestic investment and consumption,” BMI said.
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Unpredictability is only part of the story, in general a high inflation rate means a degradation of life quality over time, and a lower quality of life includes a lack of access to even the most basic needs. It means having to put your children in less qualified schools, it means avoiding doctor appointments by any means necessary, it means cutting corners in every section of your life, it means a less balanced environment to live in, an environment where people get angry more easily since they are under a constant pressure as a cause of their degrading lives. No matter how hard you try, your life quality only goes downhill, never up.</p>
|
|||
|
|
|||
|
<h1 id="a-weak-economys-rippling-effect">A Weak Economy’s Rippling Effect</h1>
|
|||
|
|
|||
|
<p>You have probably heard of <a href="https://en.wikipedia.org/wiki/Maslow's_hierarchy_of_needs">Maslow’s Hierarchy of Needs</a>. This is what it looks like:</p>
|
|||
|
|
|||
|
<p><img src="/img/discrimination/maslow.jpg" alt="Maslow's Hierarchy of Needs. A pyramid, from top to bottom: Self-Actualization, Esteem, Love/Belonging, Safety, Physiological" /></p>
|
|||
|
|
|||
|
<p>At the bottom, there are physiological needs, like health, food, water, sleep, shelter and sex. Only once these needs are fulfilled properly, you get motivated to even think about the next level. That means, if your physiological needs are not properly safisfied, you will not even think about safety, love and belonging, self-esteem or self-actualization.</p>
|
|||
|
|
|||
|
<p>Now, what all these physiological needs have in common is that they are fulfilled when there is a stable economic backbone in the country you live in. Once the economic backbone is broken, you begin losing access to these physiological needs. Slowly, but surely, you lose your motivation for self-actualization, for self-esteem, for love and belonging and for safety and you hunt for your physiological needs. Once this happens for a whole population in a country, you are left with people with only one goal in their lives: to survive <em>by any means</em>.</p>
|
|||
|
|
|||
|
<p>With no motivation for building strong friendships and relationships, no motivation for security and safety, for feeling of accomplishment and for creative acts, the population transitions towards becoming one unsafe, cold, threatening, untrustable environment with no sense of joy or creativity.</p>
|
|||
|
|
|||
|
<p>I’m driving from my friend’s house back to mine, it’s roughly 10pm and streets are a little crowded. I’m going through streets of Azadi District, when I see two children who are probably between 15 and 17, punching each other in the face and kicking each other’s stomach over a large trash container at the side of the street. They are fighting, as if for their lives, with a ferocity you can hardly imagine to find in a child of their age. These children do not look anything like your children, their hands are black from their fingertips to their elbows from collecting trash all day long; their clothes are not new, they do not change their clothes or take showers daily, and their backs are arched for hauling a large bag of trash for a whole day over their shoulder and back. They are fighting to win a trash container. This is what happens when you put pressure on the economy of a country. This is what the media is not telling you about the effects of sanctions. This is what needs to stop about these sanctions. This is what needs action from every person knowledgable to do something to stop it. Abuse, rape and misuse of children and adults alike is a significant, visible effect of sanctions that’s often overlooked.</p>
|
|||
|
|
|||
|
<p>It’s sad that I can not find any content regarding this matter in the media by searching. I think more content on these topics is necessary to help people be aware of the unethical and inhumane effects of sanctions on lives of innocent people.</p>
|
|||
|
|
|||
|
<p><img src="/img/discrimination/trash-collecting.jpg" alt="A teenager collecting trash in Iran" />
|
|||
|
<span class="image-caption">A teenage collecting trash in the streets of Tehran.</span></p>
|
|||
|
|
|||
|
<p>The rippling effects of a weakening economy are far worse and far-reaching than what the sanctions are supposed to do. I think it’s too optimistic to think sanctions to weaken an economy will prevent a country from spending money on something they want to spend on. What ends up happening, or at least has happened in case of Iran, is that the money is drained from places where it affects peoples lives, but I doubt anything has changed at the actual target.</p>
|
|||
|
|
|||
|
<h1 id="of-rolling-eyes-and-shrugs">Of Rolling Eyes and Shrugs</h1>
|
|||
|
|
|||
|
<p>Often when similar stories of this kind are shared, I am ready to see comments of people shrugging to the issue with responses like “they have to comply because it’s the law” or “that’s how you respond to a country that wants to build nuclear weapons” or similar. They just roll their eyes and shrug it off like this is how it’s supposed to be.</p>
|
|||
|
|
|||
|
<p>Sometimes, that’s true that it’s the law and the companies have to comply (though most of the time the application of the law goes way beyond necessity). What these responses get wrong is that there is no involvement by us, the people, in the decisions and policies of our country. Solely because I live my daily life in a geographical location that resides in the boundaries of a place on Earth known as “Iran” doesn’t mean I agree with the politics of this country, or that I should be isolated from the rest of the world because some people in my country make certain decisions.</p>
|
|||
|
|
|||
|
<p>What these replies get wrong is that in democratic countries, laws can change based on what people demand. Instead of shrugging these humanitarian issues off, please hear us out, and help echo our voice. You may not realize, but we, the people of Iran, do not have a say in what what politics our government follows or how it interacts with other countries, but you do have a say in yours. The only thing we can do is to spread the word.</p>
|
|||
|
|
|||
|
<p>What we feel when we see these responses is: “They are terrorists so let them be”, but we are not. We are normal people like you, with less privileges, solely because of our living region.</p>
|
|||
|
|
|||
|
<p>It seems like the Iranian people are now the common enemy of all sides of a global conflict. The ever-increasing pressure we feel is not from a single source, but rather, from all sides. We have internet censorship from the inside and restricted access from the outside. We have economic pressure from the inside, with a direct influence from the outside, and the same applies to every part of this conflict.</p>
|
|||
|
|
|||
|
<h1 id="final-message">Final Message</h1>
|
|||
|
|
|||
|
<p><a href="https://en.wikipedia.org/wiki/Racism">Racism</a> is defined as “prejudice, <a href="https://en.wikipedia.org/wiki/Discrimination">discrimination</a>, or antagonism directed towards other people because they are of a different race or ethnicity”. Sanctions, likewise, are a clear case of prejudice, discrimination and antagonism directed towards people because they are born in a certain country, or reside in a certain part of the planet.</p>
|
|||
|
|
|||
|
<p>If a person is jailed, or killed because of the color of their skin, you feel furious and protest against the act to show that racism has no place in your country. Sanctions are a case of jailing a whole country, killing the people inside by cutting their lifelines and causing lifetime distress for innocent people who didn’t do anything wrong. It’s discrimination on the scale of a whole population of millions. Although the people who are being effected by these sanctions are far away from your home, their misery is caused by your country’s policies and actions, and you have the right to stand up against these discriminations.</p>
|
|||
|
|
|||
|
<p>Ron Paul, former congressman <a href="https://twitter.com/RonPaul/status/1162067004733476864">touches on topic in an interview</a>:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>I think sanctions are really really bad, because it brings people in to think that “well I’m not quite as violent as other people who would use a drone”, well, hopefully it is a little bit less violent, but it’s every bit as dangerous, it’s still attacking personal liberties and it’s undermining the principle of trying to get along with people with free trade.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p><a href="https://en.wikipedia.org/wiki/Universal_Declaration_of_Human_Rights">The Universal Declaration of Human Rights</a>, Article 2, states:</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status.
|
|||
|
Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>That doesn’t sound like what’s happening now by enforcement of sanctions. Silence on this massive case of discrimination against people around the world must be broken, it must be recognized that discrimination, in any form, is not to be tolerated by humans.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<h3 id="links">Links</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4897941/">NCBI: Addressing the impact of economic sanctions on Iranian drug shortages in the joint comprehensive plan of action: promoting access to medicines and health diplomacy</a></li>
|
|||
|
<li><a href="https://medium.com/@hamed/yellow-badges-are-back-this-time-not-by-nazi-germany-not-for-jews-but-by-u-s-tech-companies-48e92d690176">Hamed Saeedi: Yellow badges are back. This time not by Nazi Germany &amp; not for Jews, but by U.S. tech companies</a></li>
|
|||
|
<li><a href="https://medium.com/@hamed/yellow-badges-are-back-this-time-not-by-nazi-germany-not-for-jews-but-by-u-s-tech-companies-48e92d690176">Foreign Policy: U.S. Sanctions Are Killing Cancer Patients in Iran</a></li>
|
|||
|
<li><a href="https://twitter.com/RonPaul/status/1162067004733476864">Ron Paul: “Sanctions Are A Deadly Act Of War”</a></li>
|
|||
|
</ul>
|
|||
|
</description>
|
|||
|
<pubDate>Sat, 27 Jul 2019 18:13:46 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/sanctions-discrimination-isolation-iran</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/sanctions-discrimination-isolation-iran</guid>
|
|||
|
|
|||
|
|
|||
|
<category>life,</category>
|
|||
|
|
|||
|
<category>iran</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Going Self-Hosted: Moving away from Google and others</title>
|
|||
|
<description><p>Since 3 years ago, I have always been eager to move away from Google and other privacy-invading companies. I have had my successes and failures in doing so, here I’m going to put out my stack of tools for moving away from Google and going self-hosted.</p>
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
<p>I first tried to move away from Google 3 years ago, and at the time, I did not have enough resources to self-host much. I started by creating my own email server, but I couldn’t afford a cloud storage. I also did not know about the alternatives available to Google Calendar, Google Keep, and other tools I was using at the time, so it was pretty hard keeping up that way.</p>
|
|||
|
|
|||
|
<p>After a year and a half, after my phone was stolen, I decided I will stick with Google apps with the coming of my new phone. I kept using Google services for less than a year, but I was frustrated. I had given up my privacy and control over my data for convenience, but that’s not what I wanted. So I decided I’m going to switch away again, and I will self-host the tools necessary.</p>
|
|||
|
|
|||
|
<p>A lot has changed since the first time I switched away, I will sketch below the tools that I have replaced and how.</p>
|
|||
|
|
|||
|
<h1 id="microg">microG</h1>
|
|||
|
|
|||
|
<p>If you want to avoid using Google Services on your Android phone, there is <a href="https://microg.org/">microG</a> for that. I flashed my phone with an <a href="http://aospextended.com/">AEX</a> ROM which supports microG, so it was not particularly hard to set-up on my phone, but I’ve heard it can be hard to set it up since it’s doing some trickery to replace Google’s services on your phone.</p>
|
|||
|
|
|||
|
<p>This also means you have to flash a custom ROM and root your device in order to do this, so maybe this option is not for everyone, but I think with Google Services active in your phone, you can’t really be sure what’s going on behind the curtains.</p>
|
|||
|
|
|||
|
<h1 id="email">Email</h1>
|
|||
|
|
|||
|
<p>One of the most common means of communication for us in the digital world, we exchange a lot of information through email, including personal and work-related information. As such, I deem email an important piece of privacy-sensitive information.</p>
|
|||
|
|
|||
|
<p>My solution for email is a self-hosted Postfix + Dovecot + SpamAssassin on my server. It is not the most straightforward thing to set up, by <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-a-mail-server-using-postfix-dovecot-mysql-and-spamassassin">this DigitalOcean tutorial</a> makes it all the easier.</p>
|
|||
|
|
|||
|
<p>I have also heard of <a href="https://mailinabox.email/">Mail-in-a-Box</a> which is supposed to make setting up your own mail server a breeze! I didn’t know about this at the time I set up my server, but it could be a better choice, so perhaps give it a try and let me know.</p>
|
|||
|
|
|||
|
<h1 id="cloud-storage">Cloud Storage</h1>
|
|||
|
|
|||
|
<p>A cloud storage is necessary for syncng your data among your devices and keeping your information safe from physical loss. I chose <a href="https://nextcloud.com/">Nextcloud</a> and I couldn’t be more satisfied. It has clients for every major operating system, and I use it to back up my files, synchronize my calendar and contacts between my Linux and my Android devices.</p>
|
|||
|
|
|||
|
<p>The installation and activation is fairly straightforward, and again, I followed a <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-nextcloud-on-ubuntu-16-04">DigitalOcean tutorial</a> to set up the service and have been using it since.</p>
|
|||
|
|
|||
|
<p>I also bought a DigitalOcean Space for $5/month, with a capacity of 250G, which is a fairly good price and worth its value. See <a href="https://www.digitalocean.com/community/questions/is-it-possible-to-mount-do-spaces-as-external-storage-in-nextcloud-as-i-mount-aws-s3-storage">this discussion</a> about attaching a DigitalOcean space to Nextcloud.</p>
|
|||
|
|
|||
|
<h1 id="contacts-and-calendar">Contacts and Calendar</h1>
|
|||
|
|
|||
|
<p>I learned about <a href="https://f-droid.org/packages/at.bitfire.davdroid/">DAVx</a> and <a href="https://f-droid.org/en/packages/at.bitfire.icsdroid/">ICSx</a>, which are tools for syncing your contacts and calendar, with support for Google Calendar as well. This means that I can still have access to my workplace calendar which is on Google, and have my own personal calendars synchronized using Nextcloud.</p>
|
|||
|
|
|||
|
<p>These tools integrate with whatever Calendar and Contacts application you are using on your phone, so you are free to choose whatever calendar and contacts application you like.</p>
|
|||
|
|
|||
|
<h1 id="notes">Notes</h1>
|
|||
|
|
|||
|
<p>For note-taking, I use a simple Markdown/todo.txt editor called <a href="https://f-droid.org/en/packages/net.gsantner.markor/">Markor</a> while Nextcloud handles the synchronization so I have access to my notes both on my computer and my phone. I use <a href="https://github.com/vimwiki/vimwiki">vimwiki</a> to organize and edit my notes on my computer. Nextcloud also provides extra applications for editing Markdown files on the web interface, which is great if you like doing everything in your browser.</p>
|
|||
|
|
|||
|
<h1 id="application-store">Application Store</h1>
|
|||
|
|
|||
|
<p>For downloading applications, I default to searching through <a href="https://f-droid.org/en/">F-Droid</a>, and in case I don’t find the tool I’m looking for (which I mostly do!), or I’m looking for a properietary application, such as Slack, I use <a href="https://f-droid.org/en/packages/com.dragons.aurora/">Aurora Store</a> or <a href="https://f-droid.org/en/packages/com.github.yeriomin.yalpstore/">Yalp Store</a>, which lets you search through all Google Play applications and install applications without a fuss.</p>
|
|||
|
|
|||
|
<p>Of course, you can install the official Google Play store as well if you would like to, but I personally am cautious about using any of Google’s applications.</p>
|
|||
|
|
|||
|
<h1 id="two-factor-authentication">Two-factor Authentication</h1>
|
|||
|
|
|||
|
<p>I use <a href="https://github.com/andOTP/andOTP/">andOTP</a> instead of Google Authenticator. One feature I love about andOTP is the ability to take an encrypted backup of your OTP keys, so you do not have to re-set all your two-factor authentications across all services if you ever want to switch your phone.</p>
|
|||
|
|
|||
|
<h1 id="password-manager">Password Manager</h1>
|
|||
|
|
|||
|
<p>I switched from LastPass, with its ugly, broken and distorted user experience to <a href="https://bitwarden.com/">BitWarden</a>, and I couldn’t ask for more! The user experience is far superior compared to LastPass, the extension doesn’t kill my browser’s performance and the Android application is great, too!</p>
|
|||
|
|
|||
|
<h1 id="firefox-containers">Firefox Containers</h1>
|
|||
|
|
|||
|
<p>Lastly, it’s natural that we can’t completely avoid using Google’s tools, we can just try to limit Google’s access to our data and avoid being tracked as much as possible. For this purpose, I started using Firefox Containers, and God, this is a killer feature!</p>
|
|||
|
|
|||
|
<p>So now, I have a few containers set up:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Personal: This one includes my personal accounts on websites other than Google that I want to stay logged-in on.</li>
|
|||
|
<li>Work: I’m logged into services that I use for work here, and it includes Google as well, but only for work.</li>
|
|||
|
<li>Google: This one, I use for accessing a personal Google Account I keep for YouTube and other services, but I’m not a serious user.</li>
|
|||
|
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/temporary-containers/">Temporary Containers</a>: Any websites that I have not explicitly chosen to be opened in one of the above containers, opens up in a new, temporary container, which means it doesn’t have access to any cookies or information from the other containers. I may sometimes choose to open Google or other services in Temporary Containers as well if I don’t see the necessity to be logged in.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>This means Google will not be able to track me using my account when I’m logged in to other services since they live in a different container, even though other methods such as <a href="https://clearcode.cc/blog/device-fingerprinting/">device fingerprinting</a> are still possible. With Firefox’s Tracking Protection and <a href="https://addons.mozilla.org/en-US/firefox/addon/ublock/">uBlock</a> always turned on, I am less concerned about tracking.</p>
|
|||
|
|
|||
|
<h1 id="not-the-easiet-thing">Not the easiet thing</h1>
|
|||
|
|
|||
|
<p>I have to admit, it’s not the easiest thing to move your digital life away from the giants, their products are built for maximum convenience, so you can’t expect to have that maximum convenience if you stop using those products, and I think it’s a far-fetched ideal to expect the same level of convenience using free applications and tools, but I personally think it’s worth it.</p>
|
|||
|
|
|||
|
</description>
|
|||
|
<pubDate>Mon, 11 Feb 2019 00:00:00 +0000</pubDate>
|
|||
|
<link>http://localhost:4000/self-hosted/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/self-hosted/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>life</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Mathematical Induction for proving tiling methods</title>
|
|||
|
<description><p>On my way towards self-taught data science, I’ve stumbled upon the need to be proficient with mathematical proofs, so I picked up the amazing <a href="https://www.amazon.com/How-Prove-It-Structured-Approach/dp/0521675995">How To Prove It: A Structured Approach</a> by Daniel J. Velleman; and I’ve been fascinated by mathematical proofs since then.</p>
|
|||
|
|
|||
|
<p>One of the uses for <a href="https://en.wikipedia.org/wiki/Mathematical_induction">Mathematical Induction</a> which I’ve found to be pretty cool is proving methods for tiling shapes.</p>
|
|||
|
|
|||
|
<p>Here is an example:</p>
|
|||
|
|
|||
|
<p>Suppose $n$ is a positive integer. An equilateral triangle is cut into $4^n$ congruent equilateral triangles, and one corner is removed. Show that the remaining area can be covered by trapezoidal tiles like this: <img src="/img/tiling/trapezoidal.jpg" class="inline" width="30" /></p>
|
|||
|
|
|||
|
<canvas id="tiling-triangle" width="200" height="200" class="centered"></canvas>
|
|||
|
<p><span class="image-caption">An example of n = 2. The dark tile is removed.</span></p>
|
|||
|
|
|||
|
<p>Just to be clear, by <em>cover</em> we mean covering without any overlaps, so you can’t have two overlapping trapezoidal tiles.</p>
|
|||
|
|
|||
|
<p>As with any mathematical induction solution, we start with the base case, which is $n = 1$, in that case the triangle looks like this:</p>
|
|||
|
|
|||
|
<canvas id="base-case" width="100" height="100" class="centered"></canvas>
|
|||
|
|
|||
|
<p>In this case, it’s obvious that we can cover the leftover area using trapezoidal tiles consisting of three equilateral triangles (the second row), so:</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>Base case: $n = 1$ then the triangle has $4^1 = 4$ tiles, and by removing the top-most tile, the second row can be covered using a single trapezoidal tile.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>Now for the induction step, we have to somehow show that after adding 1 to $n$, that is, by multiplying the tiles by $4$, we can still cover the triangle by trapezoidal tiles. To show this, we start by assuming we have a triangle with $4^n$ tiles, which we know can be covered by trapezoidal tiles, then we add the new tiles and show that they, too, can be covered by trapezoidal tiles.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>Induction Step: Suppose we have a triangle split into $4^n$ tiles, and we know by induction hypothesis that it can be covered by trapezoidal tiles.</p>
|
|||
|
|
|||
|
<p>Now suppose we have another triangle with $4^{n+1}$ tiles, that means, $4$ times as many triangles as our original triangle. We can then group the new bigger triangle into 4 congruent triangles, one of which we know can be split into trapezoidal tiles by removing one of it’s tiles.</p>
|
|||
|
|
|||
|
<p>For the three left triangles, we can find a neighbouring corner and assume the tile on that corner to be removed, and then cover the rest by trapezoidal tiles. Afterwards, since we had three such corners, and they are neighbouring corners, we can cover these three corners with one trapezoidal tile, thus completing the triangle.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>Now that’s a mouthful, in simpler terms, we are following these steps (for $n = 2$):</p>
|
|||
|
|
|||
|
<canvas id="n-2" width="200" height="200" class="centered"></canvas>
|
|||
|
|
|||
|
<p>First, we split the whole triangle into 4 smaller groups:</p>
|
|||
|
|
|||
|
<canvas id="n-2-grouped" width="200" height="200" class="centered"></canvas>
|
|||
|
|
|||
|
<p>Then, we know that one of the triangles can be covered by trapezoidal tiles if we remove one of it’s tiles, that’s the induction hypothesis (the case for $4^n$ which is proved in the base case):</p>
|
|||
|
|
|||
|
<canvas id="n-2-grouped-removed" width="200" height="200" class="centered"></canvas>
|
|||
|
|
|||
|
<p>Leaving the top triangle behind, we now find neighbouring corners among the three left triangles, and we assume the tiles in those corners to be removed (they are not actually removed as we are constrained to remove only one tile):</p>
|
|||
|
|
|||
|
<canvas id="n-2-grouped-neighbours" width="200" height="200" class="centered"></canvas>
|
|||
|
|
|||
|
<p>Now we can cover the rest of these triangles by a single trapezoidal tile, similar to the case of $n = 1$.</p>
|
|||
|
|
|||
|
<p>Afterwards, we see that the three neighbouring tiles form a trapezoidal tile, therefore we can now put the last piece there to complete the tiles.</p>
|
|||
|
|
|||
|
<canvas id="final" width="200" height="200" class="centered"></canvas>
|
|||
|
|
|||
|
<p>This procedure can be applied recursively on larger values of $n$ as well, so this concludes a proof of tiling an equilateral triangle divided into $4^n$ equilateral triangles using trapezoidal tiles after removing a single piece.</p>
|
|||
|
|
|||
|
<script>
|
|||
|
(function() {
|
|||
|
var tilingTriangle = document.getElementById('tiling-triangle');
|
|||
|
var c = tilingTriangle.getContext('2d');
|
|||
|
|
|||
|
function TriangleCanvas(id) {
|
|||
|
this.element = document.getElementById(id);
|
|||
|
this.context = this.element.getContext('2d');
|
|||
|
}
|
|||
|
|
|||
|
function modifyColor(c, p) {
|
|||
|
var e = document.createElement('i');
|
|||
|
e.style.background = c;
|
|||
|
var r = getComputedStyle(e).backgroundColor.slice(4, -1).split(',').map(parseFloat);
|
|||
|
return 'rgb(' + [r[0] + p, r[1] + p, r[2] + p].join(',') + ')';
|
|||
|
}
|
|||
|
|
|||
|
function dedup(list) {
|
|||
|
return list.reduce(function(newList, item) {
|
|||
|
if (!newList.some(function(a) { return deepCompare(a, item) })) {
|
|||
|
return newList.concat(item);
|
|||
|
}
|
|||
|
return newList;
|
|||
|
}, []);
|
|||
|
}
|
|||
|
|
|||
|
function deepCompare () {
|
|||
|
var i, l, leftChain, rightChain;
|
|||
|
|
|||
|
function compare2Objects (x, y) {
|
|||
|
var p;
|
|||
|
|
|||
|
// remember that NaN === NaN returns false
|
|||
|
// and isNaN(undefined) returns true
|
|||
|
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Compare primitives and functions.
|
|||
|
// Check if both arguments link to the same object.
|
|||
|
// Especially useful on the step where we compare prototypes
|
|||
|
if (x === y) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Works in case when functions are created in constructor.
|
|||
|
// Comparing dates is a common scenario. Another built-ins?
|
|||
|
// We can even handle functions passed across iframes
|
|||
|
if ((typeof x === 'function' && typeof y === 'function') ||
|
|||
|
(x instanceof Date && y instanceof Date) ||
|
|||
|
(x instanceof RegExp && y instanceof RegExp) ||
|
|||
|
(x instanceof String && y instanceof String) ||
|
|||
|
(x instanceof Number && y instanceof Number)) {
|
|||
|
return x.toString() === y.toString();
|
|||
|
}
|
|||
|
|
|||
|
// At last checking prototypes as good as we can
|
|||
|
if (!(x instanceof Object && y instanceof Object)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (x.constructor !== y.constructor) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (x.prototype !== y.prototype) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Check for infinitive linking loops
|
|||
|
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Quick checking of one object being a subset of another.
|
|||
|
// todo: cache the structure of arguments[0] for performance
|
|||
|
for (p in y) {
|
|||
|
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
else if (typeof y[p] !== typeof x[p]) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (p in x) {
|
|||
|
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
else if (typeof y[p] !== typeof x[p]) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
switch (typeof (x[p])) {
|
|||
|
case 'object':
|
|||
|
case 'function':
|
|||
|
|
|||
|
leftChain.push(x);
|
|||
|
rightChain.push(y);
|
|||
|
|
|||
|
if (!compare2Objects (x[p], y[p])) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
leftChain.pop();
|
|||
|
rightChain.pop();
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
if (x[p] !== y[p]) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
if (arguments.length < 1) {
|
|||
|
return true; //Die silently? Don't know how to handle such case, please help...
|
|||
|
// throw "Need two or more arguments to compare";
|
|||
|
}
|
|||
|
|
|||
|
for (i = 1, l = arguments.length; i < l; i++) {
|
|||
|
|
|||
|
leftChain = []; //Todo: this can be cached
|
|||
|
rightChain = [];
|
|||
|
|
|||
|
if (!compare2Objects(arguments[0], arguments[i])) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
TriangleCanvas.prototype.drawTriangle = function(x, y, size, fill, reversed) {
|
|||
|
var c = this.context;
|
|||
|
var corners = [{
|
|||
|
x: x,
|
|||
|
y: y,
|
|||
|
}, {
|
|||
|
x: x - size / 2,
|
|||
|
y: y + size,
|
|||
|
}, {
|
|||
|
x: x + size / 2,
|
|||
|
y: y + size,
|
|||
|
}];
|
|||
|
|
|||
|
if (reversed) {
|
|||
|
corners = [{
|
|||
|
x: x + size / 2,
|
|||
|
y: y,
|
|||
|
}, {
|
|||
|
x: x - size / 2,
|
|||
|
y: y,
|
|||
|
}, {
|
|||
|
x: x,
|
|||
|
y: y + size
|
|||
|
}];
|
|||
|
}
|
|||
|
|
|||
|
if (fill) {
|
|||
|
this.drawShape(corners, modifyColor(fill, 20), fill);
|
|||
|
} else {
|
|||
|
this.drawShape(corners);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TriangleCanvas.prototype.drawTrapezoid = function(tiles, size, strokeStyle, fillStyle) {
|
|||
|
var corners = tiles
|
|||
|
.map(function(o) {
|
|||
|
return { x: o[0] * size, y: o[1] * size };
|
|||
|
});
|
|||
|
|
|||
|
console.log(corners);
|
|||
|
|
|||
|
this.drawShape(corners, strokeStyle, fillStyle);
|
|||
|
}
|
|||
|
|
|||
|
TriangleCanvas.prototype.drawShape = function(corners, strokeStyle, fillStyle) {
|
|||
|
var c = this.context;
|
|||
|
c.beginPath();
|
|||
|
|
|||
|
c.moveTo(corners[0].x, corners[0].y);
|
|||
|
corners.slice(1).concat([corners[0]]).forEach(function(object, index) {
|
|||
|
c.lineTo(object.x, object.y);
|
|||
|
});
|
|||
|
|
|||
|
c.closePath();
|
|||
|
if (fillStyle) {
|
|||
|
c.fillStyle = fillStyle;
|
|||
|
c.fill();
|
|||
|
}
|
|||
|
if (strokeStyle) c.strokeStyle = strokeStyle;
|
|||
|
c.stroke();
|
|||
|
}
|
|||
|
|
|||
|
TriangleCanvas.prototype.drawSplittedTriangle = function(x, y, size, split, blocks, rest) {
|
|||
|
var c = this.context;
|
|||
|
|
|||
|
var rows = Math.sqrt(split);
|
|||
|
var rowHeight = size / rows;
|
|||
|
var triangleSize = size / rows;
|
|||
|
|
|||
|
for (var i = 0; i < rows * 2; i += 2) {
|
|||
|
var row = Math.floor(i / 2);
|
|||
|
|
|||
|
for (var j = 0; j < i + 1; j++) {
|
|||
|
var position = {
|
|||
|
x: x + triangleSize * j / 2 - (row * triangleSize / 2),
|
|||
|
y: y + row * rowHeight,
|
|||
|
};
|
|||
|
|
|||
|
var block = blocks.reduce(function(c, a) {
|
|||
|
return (a[0] === row && a[1] === j) ? (a[2] || 'black') : c;
|
|||
|
}, null);
|
|||
|
|
|||
|
this.drawTriangle(position.x, position.y, triangleSize, block || rest, j % 2 == 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var c1 = new TriangleCanvas('tiling-triangle');
|
|||
|
c1.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), [[0, 0, '#435062']], '#92afd7');
|
|||
|
|
|||
|
var c2 = new TriangleCanvas('base-case');
|
|||
|
c2.drawSplittedTriangle(50, 0, 100, 4, [[0, 0, '#435062']], '#92afd7');
|
|||
|
|
|||
|
var c3 = new TriangleCanvas('n-2');
|
|||
|
c3.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), [[0, 0, '#435062']], '#92afd7');
|
|||
|
|
|||
|
var c4 = new TriangleCanvas('n-2-grouped');
|
|||
|
var groups = [
|
|||
|
[0, 0, '#809bce'], [1, 0, '#809bce'], [1, 1, '#809bce'], [1, 2, '#809bce'],
|
|||
|
[2, 0, '#95b8d1'], [3, 0, '#95b8d1'], [3, 1, '#95b8d1'], [3, 2, '#95b8d1'],
|
|||
|
[2, 1, '#b8e0d2'], [2, 2, '#b8e0d2'], [2, 3, '#b8e0d2'], [3, 3, '#b8e0d2'],
|
|||
|
[2, 4, '#d6eadf'], [3, 4, '#d6eadf'], [3, 5, '#d6eadf'], [3, 6, '#d6eadf'],
|
|||
|
];
|
|||
|
c4.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), groups);
|
|||
|
|
|||
|
var c5 = new TriangleCanvas('n-2-grouped-removed');
|
|||
|
var groups = [
|
|||
|
[0, 0, 'rgb(90, 90, 90)'], [1, 0, '#809bce'], [1, 1, '#809bce'], [1, 2, '#809bce'],
|
|||
|
[2, 0, '#95b8d1'], [3, 0, '#95b8d1'], [3, 1, '#95b8d1'], [3, 2, '#95b8d1'],
|
|||
|
[2, 1, '#b8e0d2'], [2, 2, '#b8e0d2'], [2, 3, '#b8e0d2'], [3, 3, '#b8e0d2'],
|
|||
|
[2, 4, '#d6eadf'], [3, 4, '#d6eadf'], [3, 5, '#d6eadf'], [3, 6, '#d6eadf'],
|
|||
|
];
|
|||
|
c5.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), groups);
|
|||
|
c5.context.strokeStyle = '#ff7777';
|
|||
|
c5.context.lineWidth = 3;
|
|||
|
c5.drawTriangle(100, 0, 100);
|
|||
|
|
|||
|
var c6 = new TriangleCanvas('n-2-grouped-neighbours');
|
|||
|
var groups = [
|
|||
|
[0, 0, '#e7ecf6'], [1, 0, '#e7ecf6'], [1, 1, '#e7ecf6'], [1, 2, '#e7ecf6'],
|
|||
|
[2, 0, '#95b8d1'], [3, 0, '#95b8d1'], [3, 1, '#95b8d1'], [3, 2, '#6d8699'],
|
|||
|
[2, 1, '#b8e0d2'], [2, 2, '#b8e0d2'], [2, 3, '#b8e0d2'], [3, 3, '#657b73'],
|
|||
|
[2, 4, '#d6eadf'], [3, 4, '#89958e'], [3, 5, '#d6eadf'], [3, 6, '#d6eadf'],
|
|||
|
];
|
|||
|
c6.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), groups);
|
|||
|
|
|||
|
var trapezoids = [
|
|||
|
[[1, 2], [3, 2], [2.5, 3], [1.5, 3]],
|
|||
|
[[1, 2], [1.5, 3], [1, 4], [0, 4]],
|
|||
|
[[3, 2], [4, 4], [3, 4], [2.5, 3]],
|
|||
|
];
|
|||
|
c6.drawTrapezoid(trapezoids[0], 200 / 4, '#ff7777');
|
|||
|
c6.drawTrapezoid(trapezoids[1], 200 / 4, '#ff7777');
|
|||
|
c6.drawTrapezoid(trapezoids[2], 200 / 4, '#ff7777');
|
|||
|
|
|||
|
var c7 = new TriangleCanvas('final');
|
|||
|
var groups = [
|
|||
|
[0, 0, '#435062'], [1, 0, '#92afd7'], [1, 1, '#92afd7'], [1, 2, '#92afd7'],
|
|||
|
[2, 0, '#95b8d1'], [3, 0, '#95b8d1'], [3, 1, '#95b8d1'], [3, 2, '#95b8d1'],
|
|||
|
[2, 1, '#b8e0d2'], [2, 2, '#b8e0d2'], [2, 3, '#b8e0d2'], [3, 3, '#b8e0d2'],
|
|||
|
[2, 4, '#d6eadf'], [3, 4, '#d6eadf'], [3, 5, '#d6eadf'], [3, 6, '#d6eadf'],
|
|||
|
];
|
|||
|
c7.drawSplittedTriangle(100, 0, 200, Math.pow(4, 2), groups);
|
|||
|
|
|||
|
var trapezoids = [
|
|||
|
[[1.5, 1], [2.5, 1], [3, 2], [1, 2]],
|
|||
|
[[1, 2], [3, 2], [2.5, 3], [1.5, 3]],
|
|||
|
[[1, 2], [1.5, 3], [1, 4], [0, 4]],
|
|||
|
[[3, 2], [4, 4], [3, 4], [2.5, 3]],
|
|||
|
[[1.5, 3], [1, 4], [3, 4], [2.5, 3]],
|
|||
|
];
|
|||
|
trapezoids.forEach(function(el) {
|
|||
|
c7.drawTrapezoid(el, 200 / 4, '#ff7777');
|
|||
|
});
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
</description>
|
|||
|
<pubDate>Thu, 19 Oct 2017 00:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/mathematical-induction-proving-tiling-methods/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/mathematical-induction-proving-tiling-methods/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>math</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Typoclassopedia: Exercise solutions</title>
|
|||
|
<description><p>I wanted to get proficient in Haskell so I decided to follow <a href="http://www.stephendiehl.com/posts/essential_haskell.html">An [Essential] Haskell Reading List</a>. There I stumbled upon <a href="https://wiki.haskell.org/Typeclassopedia">Typoclassopedia</a>, while the material is great, I couldn’t find solutions for the exercises to check against, so I decided I would write my own and hopefully the solutions would get fixed in case I have gone wrong by others. So if you think a solution is wrong, let me know in the comments!</p>
|
|||
|
|
|||
|
<p>In each section below, I left some reference material for the exercises and then the solutions.</p>
|
|||
|
|
|||
|
<p>Note: The post will be updated as I progress in Typoclassopedia myself</p>
|
|||
|
|
|||
|
<h1 id="functor">Functor</h1>
|
|||
|
<h2 id="instances">Instances</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">xs</span>
|
|||
|
<span class="c1">-- or we could just say fmap = map</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">Maybe</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">g</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>((,) e) represents a container which holds an “annotation” of type e along with the actual value it holds. It might be clearer to write it as (e,), by analogy with an operator section like (1+), but that syntax is not allowed in types (although it is allowed in expressions with the TupleSections extension enabled). However, you can certainly think of it as (e,).</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>((-&gt;) e) (which can be thought of as (e -&gt;); see above), the type of functions which take a value of type e as a parameter, is a Functor. As a container, (e -&gt; a) represents a (possibly infinite) set of values of a, indexed by values of e. Alternatively, and more usefully, ((-&gt;) e) can be thought of as a context in which a value of type e is available to be consulted in a read-only fashion. This is also why ((-&gt;) e) is sometimes referred to as the reader monad; more on this later.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="exercises">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">Functor</code> instances for <code class="language-plaintext highlighter-rouge">Either e</code> and <code class="language-plaintext highlighter-rouge">((-&gt;) e)</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">instance</span> <span class="kt">Functor</span> <span class="p">(</span><span class="kt">Either</span> <span class="n">e</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="p">(</span><span class="kt">Left</span> <span class="n">e</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Left</span> <span class="n">e</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Right</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Right</span> <span class="p">(</span><span class="n">g</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="p">((</span><span class="o">-&gt;</span><span class="p">)</span> <span class="n">e</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="n">f</span> <span class="o">=</span> <span class="n">g</span> <span class="o">.</span> <span class="n">f</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">Functor</code> instances for <code class="language-plaintext highlighter-rouge">((,) e)</code> and for <code class="language-plaintext highlighter-rouge">Pair</code>, defined as below. Explain their similarities and differences.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">instance</span> <span class="kt">Functor</span> <span class="p">((,)</span> <span class="n">e</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">g</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
|
|||
|
|
|||
|
<span class="kr">data</span> <span class="kt">Pair</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Pair</span> <span class="n">a</span> <span class="n">a</span>
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">Pair</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Pair</span> <span class="n">a</span> <span class="n">b</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Pair</span> <span class="p">(</span><span class="n">g</span> <span class="n">a</span><span class="p">)</span> <span class="p">(</span><span class="n">g</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>Their similarity is in the fact that they both represent types of two values.
|
|||
|
Their difference is that <code class="language-plaintext highlighter-rouge">((,) e)</code> (tuples of two) can have values of different types (kind of <code class="language-plaintext highlighter-rouge">(,)</code> is <code class="language-plaintext highlighter-rouge">* -&gt; *</code>) while both values of <code class="language-plaintext highlighter-rouge">Pair</code> have the same type <code class="language-plaintext highlighter-rouge">a</code>, so <code class="language-plaintext highlighter-rouge">Pair</code> has kind <code class="language-plaintext highlighter-rouge">*</code>.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement a <code class="language-plaintext highlighter-rouge">Functor</code> instance for the type <code class="language-plaintext highlighter-rouge">ITree</code>, defined as</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">data</span> <span class="kt">ITree</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Leaf</span> <span class="p">(</span><span class="kt">Int</span> <span class="o">-&gt;</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
<span class="o">|</span> <span class="kt">Node</span> <span class="p">[</span><span class="kt">ITree</span> <span class="n">a</span><span class="p">]</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">ITree</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Leaf</span> <span class="n">f</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Leaf</span> <span class="p">(</span><span class="n">g</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Node</span> <span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Node</span> <span class="p">(</span><span class="n">fmap</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">g</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>To test this instance, I defined a function to apply the tree to an <code class="language-plaintext highlighter-rouge">Int</code>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">applyTree</span> <span class="o">::</span> <span class="kt">ITree</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">applyTree</span> <span class="p">(</span><span class="kt">Leaf</span> <span class="n">g</span><span class="p">)</span> <span class="n">i</span> <span class="o">=</span> <span class="p">[</span><span class="n">g</span> <span class="n">i</span><span class="p">]</span>
|
|||
|
<span class="n">applyTree</span> <span class="p">(</span><span class="kt">Node</span> <span class="kt">[]</span><span class="p">)</span> <span class="kr">_</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">applyTree</span> <span class="p">(</span><span class="kt">Node</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">))</span> <span class="n">i</span> <span class="o">=</span> <span class="n">applyTree</span> <span class="n">x</span> <span class="n">i</span> <span class="o">++</span> <span class="n">applyTree</span> <span class="p">(</span><span class="kt">Node</span> <span class="n">xs</span><span class="p">)</span> <span class="n">i</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>This is not a standard tree traversing algorithm, I just wanted it to be simple for testing.</p>
|
|||
|
|
|||
|
<p>Now test the instance:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">λ</span><span class="o">:</span> <span class="kr">let</span> <span class="n">t</span> <span class="o">=</span> <span class="kt">Node</span> <span class="p">[</span><span class="kt">Node</span> <span class="p">[</span><span class="kt">Leaf</span> <span class="p">(</span><span class="o">+</span><span class="mi">5</span><span class="p">),</span> <span class="kt">Leaf</span> <span class="p">(</span><span class="o">+</span><span class="mi">1</span><span class="p">)],</span> <span class="kt">Leaf</span> <span class="p">(</span><span class="o">*</span><span class="mi">2</span><span class="p">)]</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="n">applyTree</span> <span class="n">t</span> <span class="mi">1</span>
|
|||
|
<span class="p">[</span><span class="mi">6</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="n">applyTree</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">id</span> <span class="n">t</span><span class="p">)</span> <span class="mi">1</span>
|
|||
|
<span class="p">[</span><span class="mi">6</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="n">applyTree</span> <span class="p">(</span><span class="n">fmap</span> <span class="p">(</span><span class="o">+</span><span class="mi">10</span><span class="p">)</span> <span class="n">t</span><span class="p">)</span> <span class="mi">1</span>
|
|||
|
<span class="p">[</span><span class="mi">16</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">]</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Give an example of a type of kind <code class="language-plaintext highlighter-rouge">* -&gt; *</code> which cannot be made an instance of <code class="language-plaintext highlighter-rouge">Functor</code> (without using <code class="language-plaintext highlighter-rouge">undefined</code>).</p>
|
|||
|
|
|||
|
<p>I don’t know the answer to this one yet!</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Is this statement true or false?</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>The composition of two <code class="language-plaintext highlighter-rouge">Functor</code>s is also a <code class="language-plaintext highlighter-rouge">Functor</code>.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>If false, give a counterexample; if true, prove it by exhibiting some appropriate Haskell code.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>It’s true, and can be proved by the following function:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">ffmap</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Functor</span> <span class="n">f</span><span class="p">,</span> <span class="kt">Functor</span> <span class="n">j</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">j</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">j</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
<span class="n">ffmap</span> <span class="n">g</span> <span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">g</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>You can test this on arbitrary compositions of <code class="language-plaintext highlighter-rouge">Functor</code>s:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">main</span> <span class="o">=</span> <span class="kr">do</span>
|
|||
|
<span class="kr">let</span> <span class="n">result</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="p">(</span><span class="kt">Either</span> <span class="kt">String</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">=</span> <span class="n">ffmap</span> <span class="p">(</span><span class="o">+</span> <span class="mi">2</span><span class="p">)</span> <span class="p">(</span><span class="kt">Just</span> <span class="o">.</span> <span class="kt">Right</span> <span class="o">$</span> <span class="mi">5</span><span class="p">)</span>
|
|||
|
<span class="n">print</span> <span class="n">result</span> <span class="c1">-- (Just (Right 7))</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="functor-laws">Functor Laws</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fmap</span> <span class="n">id</span> <span class="o">=</span> <span class="n">id</span>
|
|||
|
<span class="n">fmap</span> <span class="p">(</span><span class="n">g</span> <span class="o">.</span> <span class="n">h</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">g</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">h</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-1">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Although it is not possible for a Functor instance to satisfy the first Functor law but not the second (excluding undefined), the reverse is possible. Give an example of a (bogus) Functor instance which satisfies the second law but not the first.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>This is easy, consider this instance:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">[]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">g</span> <span class="n">x</span><span class="o">:</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">xs</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>Then, you can test the first and second laws:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err">λ</span><span class="o">:</span> <span class="n">fmap</span> <span class="n">id</span> <span class="kt">[]</span> <span class="c1">-- [1], breaks the first law</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="n">fmap</span> <span class="p">((</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="o">+</span><span class="mi">2</span><span class="p">))</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span> <span class="c1">-- [4, 5], second law holds</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="n">fmap</span> <span class="p">(</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">.</span> <span class="n">fmap</span> <span class="p">(</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span> <span class="o">$</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span> <span class="c1">-- [4, 5]</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Which laws are violated by the evil Functor instance for list shown above: both laws, or the first law alone? Give specific counterexamples.</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">-- Evil Functor instance</span>
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">xs</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>The instance defined breaks the first law (<code class="language-plaintext highlighter-rouge">fmap id [1] -- [1,1]</code>), but holds for the second law.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="category-theory">Category Theory</h1>
|
|||
|
|
|||
|
<p>The Functor section links to <a href="https://en.wikibooks.org/wiki/Haskell/Category_theory">Category Theory</a>, so here I’m going to cover the exercises of that page, too.</p>
|
|||
|
|
|||
|
<h2 id="introduction-to-categories">Introduction to categories</h2>
|
|||
|
|
|||
|
<h3 id="category-laws">Category laws:</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>The compositions of morphisms need to be <strong>associative</strong>:</p>
|
|||
|
|
|||
|
<p>$f \circ (g \circ h) = (f \circ g) \circ h$</p>
|
|||
|
</li>
|
|||
|
<li>The category needs to be <strong>closed</strong> under the composition operator. So if $f : B \to C$ and $g: A \to B$, then there must be some $h: A \to C$ in the category such that $h = f \circ g$.</li>
|
|||
|
<li>Every object $A$ in a category must have an identity morphism, $id_A : A \to A$ that is an identity of composition with other morphisms. So for every morphism $g: A \to B$:
|
|||
|
$g \circ id_A = id_B \circ g = g$.</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h3 id="exercises-2">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>As was mentioned, any partial order $(P, \leq)$ is a category with objects as the elements of P and a morphism between elements a and b iff $a \leq b$. Which of the above laws guarantees the transitivity of $\leq$?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>The second law, which states that the category needs to be closed under the composition operator guarantess that because we have a morphism $a \leq b$, and another morphism $b \leq c$, there must also be some other morphism such that $a \leq c$.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>If we add another morphism to the above example, as illustrated below, it fails to be a category. Why? Hint: think about associativity of the composition operation.</p>
|
|||
|
|
|||
|
<p><img src="/img/typoclassopedia/not-a-cat.png" alt="not a category, an additional h: B -&gt; A" /></p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>The first law does not hold:</p>
|
|||
|
|
|||
|
<p>$f \circ (g \circ h) = (f \circ g) \circ h$</p>
|
|||
|
|
|||
|
<p>To see that, we can evaluate each side to get an inequality:</p>
|
|||
|
|
|||
|
<p>$g \circ h = id_B$</p>
|
|||
|
|
|||
|
<p>$f \circ g = id_A$</p>
|
|||
|
|
|||
|
<p>$f \circ (g \circ h) = f \circ id_B = f$</p>
|
|||
|
|
|||
|
<p>$(f \circ g) \circ h = id_A \circ h = h$</p>
|
|||
|
|
|||
|
<p>$f \neq h$</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="functors">Functors</h2>
|
|||
|
|
|||
|
<h3 id="functor-laws-1">Functor laws:</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Given an identity morphism $id_A$ on an object $A$, $F(id_A)$ must be the identity morphism on $F(A)$, so:
|
|||
|
$F(id_A) = id_{F(A)}$</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Functors must distribute over morphism composition:
|
|||
|
$F(f \circ g) = F(f) \circ F(g)$</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h3 id="exercises-3">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Check the functor laws for the diagram below.</p>
|
|||
|
|
|||
|
<p><img src="/img/typoclassopedia/functor-diagram.png" alt="functor diagram" /></p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>The first law is obvious as it’s directly written, the pale blue dotted arrows from $id_C$ to $F(id_C) = id_{F(C)}$ and $id_A$ and $id_B$ to $F(id_A) = F(id_B) = id_{F(A)} = id_{F(B)}$ show this.</p>
|
|||
|
|
|||
|
<p>The second law also holds, the only compositions in category $C$ are between $f$ and identities, and $g$ and identities, there is no composition between $f$ and $g$.</p>
|
|||
|
|
|||
|
<p>(Note: The second law always hold as long as the first one does, as was seen in Typoclassopedia)</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Check the laws for the Maybe and List functors.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">g</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">xs</span>
|
|||
|
|
|||
|
<span class="c1">-- check the first law for each part:</span>
|
|||
|
<span class="n">fmap</span> <span class="n">id</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">fmap</span> <span class="n">id</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">id</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">id</span> <span class="n">xs</span> <span class="o">=</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">id</span> <span class="n">xs</span> <span class="c1">-- the first law holds recursively</span>
|
|||
|
|
|||
|
<span class="c1">-- check the second law for each part:</span>
|
|||
|
<span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="kt">[]</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">xs</span> <span class="o">=</span> <span class="n">f</span> <span class="p">(</span><span class="n">g</span> <span class="n">x</span><span class="p">)</span> <span class="o">:</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">xs</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">))</span> <span class="o">=</span> <span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="n">g</span> <span class="n">x</span> <span class="o">:</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="n">f</span> <span class="p">(</span><span class="n">g</span> <span class="n">x</span><span class="p">)</span> <span class="o">:</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">xs</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">Maybe</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span>
|
|||
|
<span class="n">fmap</span> <span class="kr">_</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">g</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1">-- check the first law for each part:</span>
|
|||
|
<span class="n">fmap</span> <span class="n">id</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="n">fmap</span> <span class="n">id</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">id</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="n">a</span>
|
|||
|
|
|||
|
<span class="c1">-- check the second law for each part:</span>
|
|||
|
<span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="n">fmap</span> <span class="p">(</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">((</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">f</span> <span class="p">(</span><span class="n">g</span> <span class="n">x</span><span class="p">))</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">g</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">x</span><span class="p">))</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">f</span> <span class="p">(</span><span class="n">g</span> <span class="n">x</span><span class="p">))</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">((</span><span class="n">f</span> <span class="o">.</span> <span class="n">g</span><span class="p">)</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="applicative">Applicative</h1>
|
|||
|
|
|||
|
<h2 id="laws">Laws</h2>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>The identity law:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">pure</span> <span class="n">id</span> <span class="o">&lt;*&gt;</span> <span class="n">v</span> <span class="o">=</span> <span class="n">v</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Homomorphism:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">pure</span> <span class="n">f</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">x</span> <span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>Intuitively, applying a non-effectful function to a non-effectful argument in an effectful context is the same as just applying the function to the argument and then injecting the result into the context with pure.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Interchange:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">y</span> <span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">$</span> <span class="n">y</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">u</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>Intuitively, this says that when evaluating the application of an effectful function to a pure argument, the order in which we evaluate the function and its argument doesn’t matter.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Composition:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="n">v</span> <span class="o">&lt;*&gt;</span> <span class="n">w</span><span class="p">)</span> <span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">.</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="n">v</span> <span class="o">&lt;*&gt;</span> <span class="n">w</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>This one is the trickiest law to gain intuition for. In some sense it is expressing a sort of associativity property of (<code class="language-plaintext highlighter-rouge">&lt;*&gt;</code>). The reader may wish to simply convince themselves that this law is type-correct.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h3 id="exercises-4">Exercises</h3>
|
|||
|
|
|||
|
<p>(Tricky) One might imagine a variant of the interchange law that says something about applying a pure function to an effectful argument. Using the above laws, prove that</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pure</span> <span class="n">f</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">f</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pure</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">f</span>
|
|||
|
<span class="o">=</span> <span class="p">(</span><span class="n">pure</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">f</span> <span class="c1">-- &lt;*&gt; is left-associative</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">$</span> <span class="n">f</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="n">pure</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span><span class="p">)</span> <span class="c1">-- interchange</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">.</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="p">(</span><span class="o">$</span> <span class="n">f</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="c1">-- composition</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">((</span><span class="o">$</span> <span class="n">f</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">)))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="c1">-- homomorphism</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">((</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">)</span> <span class="n">f</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">)))</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span> <span class="c1">-- identical</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="n">f</span> <span class="o">&lt;*&gt;</span> <span class="n">x</span>
|
|||
|
</code></pre></div></div>
|
|||
|
<p>Explanation of the last transformation:</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">flip ($)</code> has type <code class="language-plaintext highlighter-rouge">a -&gt; (a -&gt; c) -&gt; c</code>, intuitively, it first takes an argument of type <code class="language-plaintext highlighter-rouge">a</code>, then a function that accepts that argument, and in the end it calls the function with the first argument. So <code class="language-plaintext highlighter-rouge">(flip ($) 5)</code> takes as argument a function which gets called with <code class="language-plaintext highlighter-rouge">5</code> as it’s argument. If we pass <code class="language-plaintext highlighter-rouge">(+ 2)</code> to <code class="language-plaintext highlighter-rouge">(flip ($) 5)</code>, we get <code class="language-plaintext highlighter-rouge">(flip ($) 5) (+2)</code> which is equivalent to the expression <code class="language-plaintext highlighter-rouge">(+2) $ 5</code>, evaluating to <code class="language-plaintext highlighter-rouge">7</code>.</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">flip ($) f</code> is equivalent to <code class="language-plaintext highlighter-rouge">\x -&gt; x $ f</code>, that means, it takes as input a function and calls it with the function <code class="language-plaintext highlighter-rouge">f</code> as argument.</p>
|
|||
|
|
|||
|
<p>The composition of these functions works like this: First <code class="language-plaintext highlighter-rouge">flip ($)</code> takes <code class="language-plaintext highlighter-rouge">x</code> as it’s first argument, and returns a function <code class="language-plaintext highlighter-rouge">(flip ($) x)</code>, this function is awaiting a function as it’s last argument, which will be called with <code class="language-plaintext highlighter-rouge">x</code> as it’s argument. Now this function <code class="language-plaintext highlighter-rouge">(flip ($) x)</code> is passed to <code class="language-plaintext highlighter-rouge">flip ($) f</code>, or to write it’s equivalent <code class="language-plaintext highlighter-rouge">(\x -&gt; x $ f) (flip ($) x)</code>, this results in the expression <code class="language-plaintext highlighter-rouge">(flip ($) x) f</code>, which is equivalent to <code class="language-plaintext highlighter-rouge">f $ x</code>.</p>
|
|||
|
|
|||
|
<p>You can check the type of <code class="language-plaintext highlighter-rouge">(flip ($) f) . (flip ($))</code> is something like this (depending on your function <code class="language-plaintext highlighter-rouge">f</code>):</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">λ</span><span class="o">:</span> <span class="kr">let</span> <span class="n">f</span> <span class="o">=</span> <span class="n">sqrt</span>
|
|||
|
<span class="err">λ</span><span class="o">:</span> <span class="o">:</span><span class="n">t</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">)</span> <span class="n">f</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span>
|
|||
|
<span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">)</span> <span class="n">f</span><span class="p">)</span> <span class="o">.</span> <span class="p">(</span><span class="n">flip</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="o">::</span> <span class="kt">Floating</span> <span class="n">c</span> <span class="o">=&gt;</span> <span class="n">c</span> <span class="o">-&gt;</span> <span class="n">c</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Also see <a href="https://stackoverflow.com/questions/46503793/applicative-prove-pure-f-x-pure-flip-x-pure-f/46505868#46505868">this question on Stack Overflow</a> which includes alternative proofs.</p>
|
|||
|
|
|||
|
<h2 id="instances-1">Instances</h2>
|
|||
|
|
|||
|
<p>Applicative instance of lists as a collection of values:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">newtype</span> <span class="kt">ZipList</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="p">{</span> <span class="n">getZipList</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="p">}</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Applicative</span> <span class="kt">ZipList</span> <span class="kr">where</span>
|
|||
|
<span class="n">pure</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">ZipList</span> <span class="n">a</span>
|
|||
|
<span class="n">pure</span> <span class="o">=</span> <span class="n">undefined</span> <span class="c1">-- exercise</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">&lt;*&gt;</span><span class="p">)</span> <span class="o">::</span> <span class="kt">ZipList</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">ZipList</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">ZipList</span> <span class="n">b</span>
|
|||
|
<span class="p">(</span><span class="kt">ZipList</span> <span class="n">gs</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="kt">ZipList</span> <span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="p">(</span><span class="n">zipWith</span> <span class="p">(</span><span class="o">$</span><span class="p">)</span> <span class="n">gs</span> <span class="n">xs</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Applicative instance of lists as a non-deterministic computation context:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">instance</span> <span class="kt">Applicative</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">pure</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">pure</span> <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">&lt;*&gt;</span><span class="p">)</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">gs</span> <span class="o">&lt;*&gt;</span> <span class="n">xs</span> <span class="o">=</span> <span class="p">[</span> <span class="n">g</span> <span class="n">x</span> <span class="o">|</span> <span class="n">g</span> <span class="o">&lt;-</span> <span class="n">gs</span><span class="p">,</span> <span class="n">x</span> <span class="o">&lt;-</span> <span class="n">xs</span> <span class="p">]</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-5">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement an instance of <code class="language-plaintext highlighter-rouge">Applicative</code> for <code class="language-plaintext highlighter-rouge">Maybe</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Applicative</span> <span class="p">(</span><span class="kt">Maybe</span> <span class="n">a</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">pure</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span>
|
|||
|
<span class="n">pure</span> <span class="n">x</span> <span class="o">=</span> <span class="kt">Just</span> <span class="n">x</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">&lt;*&gt;</span><span class="p">)</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span>
|
|||
|
<span class="kr">_</span> <span class="o">&lt;*&gt;</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="kt">Nothing</span> <span class="o">&lt;*&gt;</span> <span class="kr">_</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
<span class="p">(</span><span class="kt">Just</span> <span class="n">f</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Determine the correct definition of <code class="language-plaintext highlighter-rouge">pure</code> for the <code class="language-plaintext highlighter-rouge">ZipList</code> instance of <code class="language-plaintext highlighter-rouge">Applicative</code>—there is only one implementation that satisfies the law relating <code class="language-plaintext highlighter-rouge">pure</code> and <code class="language-plaintext highlighter-rouge">(&lt;*&gt;)</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">newtype</span> <span class="kt">ZipList</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="p">{</span> <span class="n">getZipList</span> <span class="o">::</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="p">}</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">ZipList</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="kt">ZipList</span> <span class="n">list</span><span class="p">)</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="p">{</span> <span class="n">getZipList</span> <span class="o">=</span> <span class="n">fmap</span> <span class="n">f</span> <span class="n">list</span> <span class="p">}</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Applicative</span> <span class="kt">ZipList</span> <span class="kr">where</span>
|
|||
|
<span class="n">pure</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="o">.</span> <span class="n">pure</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="kt">ZipList</span> <span class="n">gs</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="kt">ZipList</span> <span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="kt">ZipList</span> <span class="p">(</span><span class="n">zipWith</span> <span class="p">(</span><span class="o">$</span><span class="p">)</span> <span class="n">gs</span> <span class="n">xs</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>You can check the Applicative laws for this implementation.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="utility-functions">Utility functions</h2>
|
|||
|
|
|||
|
<h3 id="exercises-6">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement a function
|
|||
|
<code class="language-plaintext highlighter-rouge">sequenceAL :: Applicative f =&gt; [f a] -&gt; f [a]</code>
|
|||
|
There is a generalized version of this, <code class="language-plaintext highlighter-rouge">sequenceA</code>, which works for any <code class="language-plaintext highlighter-rouge">Traversable</code> (see the later section on <code class="language-plaintext highlighter-rouge">Traversable</code>), but implementing this version specialized to lists is a good exercise.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">createList</span> <span class="o">=</span> <span class="n">replicate</span> <span class="mi">1</span>
|
|||
|
|
|||
|
<span class="n">sequenceAL</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="n">f</span> <span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">sequenceAL</span> <span class="o">=</span> <span class="n">foldr</span> <span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="p">((</span><span class="o">++</span><span class="p">)</span> <span class="o">.</span> <span class="n">createList</span> <span class="o">&lt;$&gt;</span> <span class="n">x</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="p">(</span><span class="n">pure</span> <span class="kt">[]</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>Explanation:</p>
|
|||
|
|
|||
|
<p>First, <code class="language-plaintext highlighter-rouge">createList</code> is a simple function for creating a list of a single element, e.g. <code class="language-plaintext highlighter-rouge">createList 2 == [2]</code>.</p>
|
|||
|
|
|||
|
<p>Now let’s take <code class="language-plaintext highlighter-rouge">sequenceAL</code> apart, first, it does a fold over the list <code class="language-plaintext highlighter-rouge">[f a]</code>, and <code class="language-plaintext highlighter-rouge">b</code> is initialized to <code class="language-plaintext highlighter-rouge">pure []</code>, which results in <code class="language-plaintext highlighter-rouge">f [a]</code> as required by the function’s output.</p>
|
|||
|
|
|||
|
<p>Inside the function, <code class="language-plaintext highlighter-rouge">createList &lt;$&gt; x</code> applies <code class="language-plaintext highlighter-rouge">createList</code> to the value inside <code class="language-plaintext highlighter-rouge">f a</code>, resulting in <code class="language-plaintext highlighter-rouge">f [a]</code>, and then <code class="language-plaintext highlighter-rouge">(++)</code> is applied to the value again, so it becomes <code class="language-plaintext highlighter-rouge">f ((++) [a])</code>, now we can apply the function <code class="language-plaintext highlighter-rouge">(++) [a]</code> to <code class="language-plaintext highlighter-rouge">b</code> by <code class="language-plaintext highlighter-rouge">((++) . createList &lt;$&gt; x) &lt;*&gt; b</code>, which results in <code class="language-plaintext highlighter-rouge">f ([a] ++ b)</code>.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="alternative-formulation">Alternative formulation</h2>
|
|||
|
|
|||
|
<h3 id="definition">Definition</h3>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">Functor</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="kt">Monoidal</span> <span class="n">f</span> <span class="kr">where</span>
|
|||
|
<span class="n">unit</span> <span class="o">::</span> <span class="n">f</span> <span class="nb">()</span>
|
|||
|
<span class="p">(</span><span class="o">**</span><span class="p">)</span> <span class="o">::</span> <span class="n">f</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="laws-1">Laws:</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Left identity</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">unit</span> <span class="o">**</span> <span class="n">v</span> <span class="err">≅</span> <span class="n">v</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Right identity</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">**</span> <span class="n">unit</span> <span class="err">≅</span> <span class="n">u</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Associativity</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">**</span> <span class="p">(</span><span class="n">v</span> <span class="o">**</span> <span class="n">w</span><span class="p">)</span> <span class="err">≅</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="n">v</span><span class="p">)</span> <span class="o">**</span> <span class="n">w</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Neutrality</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">fmap</span> <span class="p">(</span><span class="n">g</span> <span class="o">***</span> <span class="n">h</span><span class="p">)</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="n">v</span><span class="p">)</span> <span class="o">=</span> <span class="n">fmap</span> <span class="n">g</span> <span class="n">u</span> <span class="o">**</span> <span class="n">fmap</span> <span class="n">h</span> <span class="n">v</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h3 id="isomorphism">Isomorphism</h3>
|
|||
|
|
|||
|
<p>In the laws above, <code class="language-plaintext highlighter-rouge">≅</code> refers to isomorphism rather than equality. In particular we consider:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="nb">()</span><span class="p">)</span> <span class="err">≅</span> <span class="n">x</span> <span class="err">≅</span> <span class="p">(</span><span class="nb">()</span><span class="p">,</span><span class="n">x</span><span class="p">)</span>
|
|||
|
<span class="p">((</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">),</span><span class="n">z</span><span class="p">)</span> <span class="err">≅</span> <span class="p">(</span><span class="n">x</span><span class="p">,(</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">))</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-7">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">pure</code> and <code class="language-plaintext highlighter-rouge">&lt;*&gt;</code> in terms of <code class="language-plaintext highlighter-rouge">unit</code> and <code class="language-plaintext highlighter-rouge">**</code>, and vice versa.</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">unit</span> <span class="o">::</span> <span class="n">f</span> <span class="nb">()</span>
|
|||
|
<span class="n">unit</span> <span class="o">=</span> <span class="n">pure</span> <span class="nb">()</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">**</span><span class="p">)</span> <span class="o">::</span> <span class="n">f</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
<span class="n">a</span> <span class="o">**</span> <span class="n">b</span> <span class="o">=</span> <span class="n">fmap</span> <span class="p">(,)</span> <span class="n">a</span> <span class="o">&lt;*&gt;</span> <span class="n">b</span>
|
|||
|
|
|||
|
<span class="n">pure</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">a</span>
|
|||
|
<span class="n">pure</span> <span class="n">x</span> <span class="o">=</span> <span class="n">unit</span> <span class="o">**</span> <span class="n">x</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">&lt;*&gt;</span><span class="p">)</span> <span class="o">::</span> <span class="n">f</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span>
|
|||
|
<span class="n">f</span> <span class="o">&lt;*&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">f</span> <span class="o">**</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="p">(</span><span class="n">f</span> <span class="o">**</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Are there any <code class="language-plaintext highlighter-rouge">Applicative</code> instances for which there are also functions <code class="language-plaintext highlighter-rouge">f () -&gt; ()</code> and <code class="language-plaintext highlighter-rouge">f (a,b) -&gt; (f a, f b)</code>, satisfying some “reasonable” laws?</p>
|
|||
|
|
|||
|
<p>The <a href="https://wiki.haskell.org/Typeclassopedia#Arrow"><code class="language-plaintext highlighter-rouge">Arrow</code></a> type class seems to satisfy these criteria.</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">first</span> <span class="n">unit</span> <span class="o">=</span> <span class="nb">()</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="n">id</span> <span class="o">***</span> <span class="n">f</span><span class="p">)</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">,</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>(Tricky) Prove that given your implementations from the first exercise, the usual Applicative laws and the Monoidal laws stated above are equivalent.</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Identity Law</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">pure</span> <span class="n">id</span> <span class="o">&lt;*&gt;</span> <span class="n">v</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">((</span><span class="n">unit</span> <span class="o">**</span> <span class="n">id</span><span class="p">)</span> <span class="o">**</span> <span class="n">v</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">id</span> <span class="o">**</span> <span class="n">v</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="n">id</span> <span class="n">v</span>
|
|||
|
<span class="o">=</span> <span class="n">v</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Homomorphism</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">pure</span> <span class="n">f</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">x</span>
|
|||
|
<span class="o">=</span> <span class="p">(</span><span class="n">unit</span> <span class="o">**</span> <span class="n">f</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="n">unit</span> <span class="o">**</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="p">(</span><span class="n">unit</span> <span class="o">**</span> <span class="n">f</span><span class="p">)</span> <span class="p">(</span><span class="n">unit</span> <span class="o">**</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="p">(</span><span class="n">f</span> <span class="o">**</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="n">f</span> <span class="n">x</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Interchange</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="n">pure</span> <span class="n">y</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="p">(</span><span class="n">unit</span> <span class="o">**</span> <span class="n">y</span><span class="p">))</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="n">y</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">u</span> <span class="o">$</span><span class="p">)</span> <span class="n">y</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="o">$</span> <span class="n">y</span><span class="p">)</span> <span class="n">u</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">$</span> <span class="n">y</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">u</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Composition</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="n">v</span> <span class="o">&lt;*&gt;</span> <span class="n">w</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="p">(</span><span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">v</span> <span class="o">**</span> <span class="n">w</span><span class="p">)))</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">uncurry</span> <span class="p">(</span><span class="o">$</span><span class="p">))</span> <span class="p">(</span><span class="n">u</span> <span class="o">**</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">v</span> <span class="n">w</span><span class="p">))</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="n">u</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">v</span> <span class="n">w</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="n">u</span> <span class="o">.</span> <span class="n">v</span><span class="p">)</span> <span class="n">w</span>
|
|||
|
<span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="o">.</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="n">u</span> <span class="o">&lt;*&gt;</span> <span class="n">v</span> <span class="o">&lt;*&gt;</span> <span class="n">w</span> <span class="o">=</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="monad">Monad</h1>
|
|||
|
|
|||
|
<h2 id="definition-1">Definition</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">Applicative</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Monad</span> <span class="n">m</span> <span class="kr">where</span>
|
|||
|
<span class="n">return</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span>
|
|||
|
<span class="p">(</span><span class="o">&gt;&gt;=</span><span class="p">)</span> <span class="o">::</span> <span class="n">m</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">b</span>
|
|||
|
<span class="p">(</span><span class="o">&gt;&gt;</span><span class="p">)</span> <span class="o">::</span> <span class="n">m</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">b</span>
|
|||
|
<span class="n">m</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">=</span> <span class="n">m</span> <span class="o">&gt;&gt;=</span> <span class="nf">\</span><span class="kr">_</span> <span class="o">-&gt;</span> <span class="n">n</span>
|
|||
|
|
|||
|
<span class="n">fail</span> <span class="o">::</span> <span class="kt">String</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h2 id="instances-2">Instances</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">instance</span> <span class="kt">Monad</span> <span class="kt">Maybe</span> <span class="kr">where</span>
|
|||
|
<span class="n">return</span> <span class="o">::</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span>
|
|||
|
<span class="n">return</span> <span class="o">=</span> <span class="kt">Just</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="o">&gt;&gt;=</span><span class="p">)</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span>
|
|||
|
<span class="p">(</span><span class="kt">Just</span> <span class="n">x</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">g</span> <span class="n">x</span>
|
|||
|
<span class="kt">Nothing</span> <span class="o">&gt;&gt;=</span> <span class="kr">_</span> <span class="o">=</span> <span class="kt">Nothing</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-8">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement a <code class="language-plaintext highlighter-rouge">Monad</code> instance for the list constructor, <code class="language-plaintext highlighter-rouge">[]</code>. Follow the types!</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Monad</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">return</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
|
|||
|
<span class="kt">[]</span> <span class="o">&gt;&gt;</span> <span class="kr">_</span> <span class="o">=</span> <span class="kt">[]</span>
|
|||
|
<span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span> <span class="o">=</span> <span class="n">f</span> <span class="n">x</span> <span class="o">:</span> <span class="n">xs</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement a <code class="language-plaintext highlighter-rouge">Monad</code> instance for <code class="language-plaintext highlighter-rouge">((-&gt;) e)</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Monad</span> <span class="p">((</span><span class="o">-&gt;</span><span class="p">)</span> <span class="n">e</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">return</span> <span class="n">x</span> <span class="o">=</span> <span class="n">const</span> <span class="n">x</span>
|
|||
|
|
|||
|
<span class="n">g</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span> <span class="o">=</span> <span class="n">f</span> <span class="o">.</span> <span class="n">g</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">Functor</code> and <code class="language-plaintext highlighter-rouge">Monad</code> instance for <code class="language-plaintext highlighter-rouge">Free f</code>, defined as:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">data</span> <span class="kt">Free</span> <span class="n">f</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Var</span> <span class="n">a</span>
|
|||
|
<span class="o">|</span> <span class="kt">Node</span> <span class="p">(</span><span class="n">f</span> <span class="p">(</span><span class="kt">Free</span> <span class="n">f</span> <span class="n">a</span><span class="p">))</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>You may assume that <code class="language-plaintext highlighter-rouge">f</code> has a <code class="language-plaintext highlighter-rouge">Functor</code> instance. This is known as the <em>free monad</em> built from the functor f.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Functor</span> <span class="p">(</span><span class="kt">Free</span> <span class="n">f</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Var</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Var</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Node</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Node</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Monad</span> <span class="p">(</span><span class="kt">Free</span> <span class="n">f</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">return</span> <span class="n">x</span> <span class="o">=</span> <span class="kt">Var</span> <span class="n">x</span>
|
|||
|
|
|||
|
<span class="p">(</span><span class="kt">Var</span> <span class="n">x</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span> <span class="o">=</span> <span class="kt">Var</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
<span class="p">(</span><span class="kt">Node</span> <span class="n">x</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span> <span class="o">=</span> <span class="kt">Node</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="intuition">Intuition</h2>
|
|||
|
|
|||
|
<h3 id="exercises-9">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">(&gt;&gt;=)</code> in terms of <code class="language-plaintext highlighter-rouge">fmap</code> (or <code class="language-plaintext highlighter-rouge">liftM</code>) and <code class="language-plaintext highlighter-rouge">join</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">a</span> <span class="o">&gt;&gt;=</span> <span class="n">f</span> <span class="o">=</span> <span class="n">join</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">f</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Now implement <code class="language-plaintext highlighter-rouge">join</code> and <code class="language-plaintext highlighter-rouge">fmap</code> (<code class="language-plaintext highlighter-rouge">liftM</code>) in terms of <code class="language-plaintext highlighter-rouge">(&gt;&gt;=)</code> and <code class="language-plaintext highlighter-rouge">return</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">fmap</span> <span class="n">f</span> <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">&gt;&gt;=</span> <span class="p">(</span><span class="n">return</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
<span class="n">join</span> <span class="n">m</span> <span class="o">=</span> <span class="n">m</span> <span class="o">&gt;&gt;=</span> <span class="n">id</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="laws-2">Laws</h2>
|
|||
|
|
|||
|
<p>Standard:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">return</span> <span class="n">a</span> <span class="o">&gt;&gt;=</span> <span class="n">k</span> <span class="o">=</span> <span class="n">k</span> <span class="n">a</span>
|
|||
|
<span class="n">m</span> <span class="o">&gt;&gt;=</span> <span class="n">return</span> <span class="o">=</span> <span class="n">m</span>
|
|||
|
<span class="n">m</span> <span class="o">&gt;&gt;=</span> <span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">k</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">h</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">m</span> <span class="o">&gt;&gt;=</span> <span class="n">k</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">h</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>In terms of <code class="language-plaintext highlighter-rouge">&gt;=&gt;</code>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">return</span> <span class="o">&gt;=&gt;</span> <span class="n">g</span> <span class="o">=</span> <span class="n">g</span>
|
|||
|
<span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="n">return</span> <span class="o">=</span> <span class="n">g</span>
|
|||
|
<span class="p">(</span><span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="n">h</span><span class="p">)</span> <span class="o">&gt;=&gt;</span> <span class="n">k</span> <span class="o">=</span> <span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="p">(</span><span class="n">h</span> <span class="o">&gt;=&gt;</span> <span class="n">k</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-10">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Given the definition <code class="language-plaintext highlighter-rouge">g &gt;=&gt; h = \x -&gt; g x &gt;&gt;= h</code>, prove the equivalence of the above laws and the standard monad laws.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">return</span> <span class="o">&gt;=&gt;</span> <span class="n">g</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">return</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">g</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">x</span>
|
|||
|
<span class="o">=</span> <span class="n">g</span>
|
|||
|
|
|||
|
<span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="n">return</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">return</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">x</span>
|
|||
|
<span class="o">=</span> <span class="n">g</span>
|
|||
|
|
|||
|
<span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="p">(</span><span class="n">h</span> <span class="o">&gt;=&gt;</span> <span class="n">k</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">y</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">y</span> <span class="o">&gt;&gt;=</span> <span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">h</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">k</span><span class="p">)</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">y</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">g</span> <span class="n">y</span> <span class="o">&gt;&gt;=</span> <span class="n">h</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">k</span>
|
|||
|
<span class="o">=</span> <span class="nf">\</span><span class="n">y</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">h</span><span class="p">)</span> <span class="n">y</span> <span class="o">&gt;&gt;=</span> <span class="n">k</span>
|
|||
|
<span class="o">=</span> <span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">g</span> <span class="n">x</span> <span class="o">&gt;&gt;=</span> <span class="n">h</span><span class="p">)</span> <span class="o">&gt;=&gt;</span> <span class="n">k</span>
|
|||
|
<span class="o">=</span> <span class="p">(</span><span class="n">g</span> <span class="o">&gt;=&gt;</span> <span class="n">h</span><span class="p">)</span> <span class="o">&gt;=&gt;</span> <span class="n">k</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="monad-transformers">Monad Transformers</h1>
|
|||
|
|
|||
|
<h2 id="definition-and-laws">Definition and laws</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">MonadTrans</span> <span class="n">t</span> <span class="kr">where</span>
|
|||
|
<span class="n">lift</span> <span class="o">::</span> <span class="kt">Monad</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="n">m</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">m</span> <span class="n">a</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-11">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>What is the kind of <code class="language-plaintext highlighter-rouge">t</code> in the declaration of <code class="language-plaintext highlighter-rouge">MonadTrans</code>?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">t</code> is of the kind <code class="language-plaintext highlighter-rouge">(* -&gt; *) -&gt; * -&gt; *</code>, as we see in <code class="language-plaintext highlighter-rouge">(t m) a</code>, <code class="language-plaintext highlighter-rouge">t</code> accepts a <code class="language-plaintext highlighter-rouge">Monad</code> first, which is of type <code class="language-plaintext highlighter-rouge">* -&gt; *</code>, and then
|
|||
|
another argument of kind <code class="language-plaintext highlighter-rouge">*</code>.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="composing-monads">Composing Monads</h2>
|
|||
|
|
|||
|
<h3 id="exercises-12">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">join :: M (N (M (N a))) -&gt; M (N a)</code> given <code class="language-plaintext highlighter-rouge">distrib :: N (M a) -&gt; M (N a)</code> and assuming <code class="language-plaintext highlighter-rouge">M</code> and <code class="language-plaintext highlighter-rouge">N</code> are instances of <code class="language-plaintext highlighter-rouge">Monad</code>.</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">join</span> <span class="o">::</span> <span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="p">(</span><span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">)))</span> <span class="o">-&gt;</span> <span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
<span class="n">join</span> <span class="n">m</span> <span class="o">=</span> <span class="n">distrib</span> <span class="p">((</span><span class="n">distrib</span> <span class="n">m</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">join</span><span class="p">)</span> <span class="o">&gt;&gt;=</span> <span class="n">join</span>
|
|||
|
|
|||
|
<span class="c1">-- one by one</span>
|
|||
|
<span class="kr">let</span> <span class="n">m</span> <span class="o">::</span> <span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="p">(</span><span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">)))</span>
|
|||
|
<span class="n">a</span> <span class="o">=</span> <span class="n">distrib</span> <span class="n">m</span> <span class="o">::</span> <span class="kt">N</span> <span class="p">(</span><span class="kt">M</span> <span class="p">(</span><span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">)))</span>
|
|||
|
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span> <span class="o">&gt;&gt;=</span> <span class="n">join</span> <span class="o">::</span> <span class="kt">N</span> <span class="p">(</span><span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">))</span>
|
|||
|
<span class="n">c</span> <span class="o">=</span> <span class="n">distrib</span> <span class="n">b</span> <span class="o">::</span> <span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">))</span>
|
|||
|
<span class="kr">in</span> <span class="n">c</span> <span class="o">&gt;&gt;=</span> <span class="n">join</span> <span class="o">::</span> <span class="kt">M</span> <span class="p">(</span><span class="kt">N</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="monadfix">MonadFix</h1>
|
|||
|
|
|||
|
<h2 id="examples-and-intuition">Examples and intuition</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">maybeFix</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span>
|
|||
|
<span class="n">maybeFix</span> <span class="n">f</span> <span class="o">=</span> <span class="n">ma</span>
|
|||
|
<span class="kr">where</span> <span class="n">ma</span> <span class="o">=</span> <span class="n">f</span> <span class="p">(</span><span class="n">fromJust</span> <span class="n">ma</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-13">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement a MonadFix instance for [].</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">listFix</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">listFix</span> <span class="n">f</span> <span class="o">=</span> <span class="n">la</span>
|
|||
|
<span class="kr">where</span> <span class="n">la</span> <span class="o">=</span> <span class="n">f</span> <span class="p">(</span><span class="n">head</span> <span class="n">la</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="foldable">Foldable</h1>
|
|||
|
|
|||
|
<h2 id="definition-2">Definition</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">class</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="kr">where</span>
|
|||
|
<span class="n">fold</span> <span class="o">::</span> <span class="kt">Monoid</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">m</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
<span class="n">foldMap</span> <span class="o">::</span> <span class="kt">Monoid</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
<span class="n">foldr</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span>
|
|||
|
<span class="n">foldr'</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span>
|
|||
|
<span class="n">foldl</span> <span class="o">::</span> <span class="p">(</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span>
|
|||
|
<span class="n">foldl'</span> <span class="o">::</span> <span class="p">(</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span>
|
|||
|
<span class="n">foldr1</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">foldl1</span> <span class="o">::</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">toList</span> <span class="o">::</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">null</span> <span class="o">::</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">length</span> <span class="o">::</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Int</span>
|
|||
|
<span class="n">elem</span> <span class="o">::</span> <span class="kt">Eq</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">maximum</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">minimum</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">sum</span> <span class="o">::</span> <span class="kt">Num</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">product</span> <span class="o">::</span> <span class="kt">Num</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h2 id="instances-and-examples">Instances and examples</h2>
|
|||
|
|
|||
|
<h3 id="exercises-14">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">fold</code> in terms of <code class="language-plaintext highlighter-rouge">foldMap</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">fold</span> <span class="o">=</span> <span class="n">foldMap</span> <span class="n">id</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>What would you need in order to implement <code class="language-plaintext highlighter-rouge">foldMap</code> in terms of <code class="language-plaintext highlighter-rouge">fold</code>?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>A <code class="language-plaintext highlighter-rouge">map</code> function should exist for the instance, so we can apply the function <code class="language-plaintext highlighter-rouge">(a -&gt; m)</code> to the container first.</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">foldMap</span> <span class="n">f</span> <span class="o">=</span> <span class="n">fold</span> <span class="o">.</span> <span class="n">map</span> <span class="n">f</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">foldMap</code> in terms of <code class="language-plaintext highlighter-rouge">foldr</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">foldMap</span> <span class="n">f</span> <span class="o">=</span> <span class="n">foldr</span> <span class="p">(</span><span class="nf">\</span><span class="n">a</span> <span class="n">b</span> <span class="o">-&gt;</span> <span class="n">mappend</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="n">b</span><span class="p">)</span> <span class="n">mempty</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">foldr</code> in terms of <code class="language-plaintext highlighter-rouge">foldMap</code> (hint: use the <code class="language-plaintext highlighter-rouge">Endo</code> monoid).</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">foldr</span> <span class="n">f</span> <span class="n">b</span> <span class="n">c</span> <span class="o">=</span> <span class="n">foldMap</span> <span class="p">(</span><span class="kt">Endo</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span> <span class="n">c</span> <span class="p">`</span><span class="n">appEndo</span><span class="p">`</span> <span class="n">b</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>What is the type of <code class="language-plaintext highlighter-rouge">foldMap . foldMap</code>? Or <code class="language-plaintext highlighter-rouge">foldMap . foldMap . foldMap</code>, etc.? What do they do?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>Each composition makes <code class="language-plaintext highlighter-rouge">foldMap</code> operate on a deeper level, so:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">foldMap</span> <span class="o">::</span> <span class="kt">Monoid</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
<span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="o">::</span> <span class="kt">Monoid</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="p">(</span><span class="n">t</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
<span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="o">::</span> <span class="kt">Monoid</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="p">(</span><span class="n">t</span> <span class="p">(</span><span class="n">t</span> <span class="n">a</span><span class="p">))</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
|
|||
|
<span class="n">foldMap</span> <span class="n">id</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="o">::</span> <span class="kt">Sum</span> <span class="kt">Int</span> <span class="c1">-- 6</span>
|
|||
|
<span class="p">(</span><span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span><span class="p">)</span> <span class="n">id</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]]</span> <span class="o">::</span> <span class="kt">Sum</span> <span class="kt">Int</span> <span class="c1">-- 6</span>
|
|||
|
<span class="p">(</span><span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="o">.</span> <span class="n">foldMap</span><span class="p">)</span> <span class="n">id</span> <span class="p">[[[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]]]</span> <span class="o">::</span> <span class="kt">Sum</span> <span class="kt">Int</span> <span class="c1">-- 6</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
<h2 id="derived-folds">Derived folds</h2>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h3 id="exercises-15">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">toList :: Foldable f =&gt; f a -&gt; [a]</code> in terms of either <code class="language-plaintext highlighter-rouge">foldr</code> or <code class="language-plaintext highlighter-rouge">foldMap</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">toList</span> <span class="o">=</span> <span class="n">foldMap</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">1</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Show how one could implement the generic version of <code class="language-plaintext highlighter-rouge">foldr</code> in terms of <code class="language-plaintext highlighter-rouge">toList</code>, assuming we had only the list-specific <code class="language-plaintext highlighter-rouge">foldr :: (a -&gt; b -&gt; b) -&gt; b -&gt; [a] -&gt; b</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">foldr</span> <span class="n">f</span> <span class="n">b</span> <span class="n">c</span> <span class="o">=</span> <span class="n">foldr</span> <span class="n">f</span> <span class="n">b</span> <span class="p">(</span><span class="n">toList</span> <span class="n">c</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Pick some of the following functions to implement: <code class="language-plaintext highlighter-rouge">concat</code>, <code class="language-plaintext highlighter-rouge">concatMap</code>, <code class="language-plaintext highlighter-rouge">and</code>, <code class="language-plaintext highlighter-rouge">or</code>, <code class="language-plaintext highlighter-rouge">any</code>, <code class="language-plaintext highlighter-rouge">all</code>, <code class="language-plaintext highlighter-rouge">sum</code>, <code class="language-plaintext highlighter-rouge">product</code>, <code class="language-plaintext highlighter-rouge">maximum(By)</code>, <code class="language-plaintext highlighter-rouge">minimum(By)</code>, <code class="language-plaintext highlighter-rouge">elem</code>, <code class="language-plaintext highlighter-rouge">notElem</code>, and <code class="language-plaintext highlighter-rouge">find</code>. Figure out how they generalize to <code class="language-plaintext highlighter-rouge">Foldable</code> and come up with elegant implementations using <code class="language-plaintext highlighter-rouge">fold</code> or <code class="language-plaintext highlighter-rouge">foldMap</code> along with appropriate <code class="language-plaintext highlighter-rouge">Monoid</code> instances.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">concat</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
|
|||
|
<span class="n">concat</span> <span class="o">=</span> <span class="n">foldMap</span> <span class="n">id</span>
|
|||
|
|
|||
|
<span class="n">concatMap</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">concatMap</span> <span class="n">f</span> <span class="o">=</span> <span class="n">foldMap</span> <span class="p">(</span><span class="n">foldMap</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">1</span> <span class="o">.</span> <span class="n">f</span><span class="p">))</span>
|
|||
|
|
|||
|
<span class="n">and</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="kt">Bool</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">and</span> <span class="o">=</span> <span class="n">getAll</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="kt">All</span>
|
|||
|
|
|||
|
<span class="n">or</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="kt">Bool</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">or</span> <span class="o">=</span> <span class="n">getAny</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="kt">Any</span>
|
|||
|
|
|||
|
<span class="n">any</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">any</span> <span class="n">f</span> <span class="o">=</span> <span class="n">getAny</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="p">(</span><span class="kt">Any</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">all</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span><span class="p">)</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">all</span> <span class="n">f</span> <span class="o">=</span> <span class="n">getAll</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="p">(</span><span class="kt">All</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">sum</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Num</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Foldable</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">sum</span> <span class="o">=</span> <span class="n">getSum</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="kt">Sum</span>
|
|||
|
|
|||
|
<span class="n">product</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Num</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Foldable</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">product</span> <span class="o">=</span> <span class="n">getProduct</span> <span class="o">.</span> <span class="n">foldMap</span> <span class="kt">Product</span>
|
|||
|
|
|||
|
<span class="c1">-- I think there are more elegant implementations for maximumBy, leave a comment</span>
|
|||
|
<span class="c1">-- if you have a suggestion</span>
|
|||
|
<span class="n">maximumBy</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Ordering</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span>
|
|||
|
<span class="n">maximumBy</span> <span class="n">f</span> <span class="n">c</span> <span class="o">=</span> <span class="n">head</span> <span class="o">$</span> <span class="n">foldMap</span> <span class="p">(</span><span class="nf">\</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span> <span class="o">|</span> <span class="n">cmp</span> <span class="n">a</span><span class="p">])</span> <span class="n">c</span>
|
|||
|
<span class="kr">where</span>
|
|||
|
<span class="n">cmp</span> <span class="n">a</span> <span class="o">=</span> <span class="n">all</span> <span class="p">(</span><span class="o">/=</span> <span class="kt">LT</span><span class="p">)</span> <span class="p">(</span><span class="n">map</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="n">lst</span><span class="p">)</span>
|
|||
|
<span class="n">lst</span> <span class="o">=</span> <span class="n">toList</span> <span class="n">c</span>
|
|||
|
|
|||
|
<span class="n">elem</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Foldable</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
|
|||
|
<span class="n">elem</span> <span class="n">x</span> <span class="n">c</span> <span class="o">=</span> <span class="n">any</span> <span class="p">(</span><span class="o">==</span><span class="n">x</span><span class="p">)</span> <span class="n">c</span>
|
|||
|
|
|||
|
<span class="n">find</span> <span class="o">::</span> <span class="kt">Foldable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span>
|
|||
|
<span class="n">find</span> <span class="n">f</span> <span class="n">c</span> <span class="o">=</span> <span class="n">listToMaybe</span> <span class="o">$</span> <span class="n">foldMap</span> <span class="p">(</span><span class="nf">\</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span> <span class="o">|</span> <span class="n">f</span> <span class="n">a</span><span class="p">])</span> <span class="n">c</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="utility-functions-1">Utility functions</h2>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>
|
|||
|
<p><code class="language-plaintext highlighter-rouge">sequenceA_ :: (Applicative f, Foldable t) =&gt; t (f a) -&gt; f ()</code> takes a container full of computations and runs them in sequence, discarding the results (that is, they are used only for their effects). Since the results are discarded, the container only needs to be Foldable. (Compare with <code class="language-plaintext highlighter-rouge">sequenceA :: (Applicative f, Traversable t) =&gt; t (f a) -&gt; f (t a)</code>, which requires a stronger Traversable constraint in order to be able to reconstruct a container of results having the same shape as the original container.)</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p><code class="language-plaintext highlighter-rouge">traverse_ :: (Applicative f, Foldable t) =&gt; (a -&gt; f b) -&gt; t a -&gt; f ()</code> applies the given function to each element in a foldable container and sequences the effects (but discards the results).</p>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="exercises-16">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">traverse_</code> in terms of <code class="language-plaintext highlighter-rouge">sequenceA_</code> and vice versa. One of these will need an extra constraint. What is it?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">sequenceA_</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Applicative</span> <span class="n">f</span><span class="p">,</span> <span class="kt">Foldable</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="nb">()</span>
|
|||
|
<span class="n">sequenceA_</span> <span class="o">=</span> <span class="n">traverse_</span> <span class="n">id</span>
|
|||
|
|
|||
|
<span class="n">traverse_</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Applicative</span> <span class="n">f</span><span class="p">,</span> <span class="kt">Foldable</span> <span class="n">t</span><span class="p">,</span> <span class="kt">Functor</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="nb">()</span>
|
|||
|
<span class="n">traverse_</span> <span class="n">f</span> <span class="n">c</span> <span class="o">=</span> <span class="n">sequenceA_</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">f</span> <span class="n">c</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>The additional constraint for implementing <code class="language-plaintext highlighter-rouge">traverse_</code> in terms of <code class="language-plaintext highlighter-rouge">sequenceA_</code> is the requirement of the <code class="language-plaintext highlighter-rouge">Foldable</code> instance <code class="language-plaintext highlighter-rouge">t</code> to be a <code class="language-plaintext highlighter-rouge">Functor</code> as well.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="traversable">Traversable</h1>
|
|||
|
|
|||
|
<h2 id="intuition-1">Intuition</h2>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">traverse</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">t</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
<span class="n">sequenceA</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="n">t</span> <span class="p">(</span><span class="n">f</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">t</span> <span class="n">a</span><span class="p">)</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exercises-17">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>There are at least two natural ways to turn a tree of lists into a list of trees. What are they, and why?</p>
|
|||
|
|
|||
|
<p>Note: I’m not really sure whether my solution is <em>natural</em>, I think the question is rather ambiguous in the sense that it’s not clear whether the trees in the final list of trees can have lists as their values, i.e. <code class="language-plaintext highlighter-rouge">Tree [Int] -&gt; [Tree [Int]]</code> is valid or only <code class="language-plaintext highlighter-rouge">Tree [Int] -&gt; [Tree Int]</code> is, but let me know if you think otherwise.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>One way is to put each <code class="language-plaintext highlighter-rouge">Node</code>, <code class="language-plaintext highlighter-rouge">Leaf</code> or <code class="language-plaintext highlighter-rouge">Empty</code> in a list in-order, this way the structure of the tree can be recovered from the list, here is a quick sketch (<code class="language-plaintext highlighter-rouge">[]</code> is an arbitrary list):</p>
|
|||
|
|
|||
|
<p><img src="/img/typoclassopedia/tree.jpg" alt="tree to list" /></p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">let</span> <span class="n">tree</span> <span class="o">=</span> <span class="kt">Node</span> <span class="p">(</span><span class="kt">Node</span> <span class="p">(</span><span class="kt">Leaf</span> <span class="kt">[]</span><span class="p">)</span> <span class="kt">Empty</span><span class="p">)</span> <span class="kt">[]</span> <span class="p">(</span><span class="kt">Leaf</span> <span class="kt">[]</span><span class="p">)</span>
|
|||
|
<span class="kr">let</span> <span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="kt">Node</span> <span class="kt">Empty</span> <span class="kt">[]</span> <span class="kt">Empty</span><span class="p">,</span> <span class="kt">Node</span> <span class="kt">Empty</span> <span class="kt">[]</span> <span class="kt">Empty</span><span class="p">,</span> <span class="kt">Leaf</span> <span class="kt">[]</span><span class="p">,</span> <span class="kt">Empty</span><span class="p">,</span> <span class="kt">Leaf</span> <span class="kt">[]</span><span class="p">]</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Give a natural way to turn a list of trees into a tree of lists.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>To recover the original tree from the list of trees, whenever we encounter a <code class="language-plaintext highlighter-rouge">Node</code> in the list, we catch the next three values as left, value, and right nodes of the original node.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>What is the type of <code class="language-plaintext highlighter-rouge">traverse . traverse</code>? What does it do?</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="n">traverse</span> <span class="o">.</span> <span class="n">traverse</span><span class="p">)</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="p">(</span><span class="n">t2</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">t</span> <span class="p">(</span><span class="n">t2</span> <span class="n">b</span><span class="p">))</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>It traverses on a deeper level, retaining the structure of the first level.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">traverse</code> in terms of <code class="language-plaintext highlighter-rouge">sequenceA</code>, and vice versa.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">sequenceA</span> <span class="o">=</span> <span class="n">traverse</span> <span class="n">id</span>
|
|||
|
|
|||
|
<span class="n">traverseA</span> <span class="n">f</span> <span class="n">c</span> <span class="o">=</span> <span class="n">sequenceA</span> <span class="p">(</span><span class="n">fmap</span> <span class="n">f</span> <span class="n">c</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="instances-and-examples-1">Instances and examples</h2>
|
|||
|
|
|||
|
<h3 id="exercises-18">Exercises</h3>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">fmap</code> and <code class="language-plaintext highlighter-rouge">foldMap</code> using only the <code class="language-plaintext highlighter-rouge">Traversable</code> methods. (Note that the <code class="language-plaintext highlighter-rouge">Traversable</code> module provides these implementations as <code class="language-plaintext highlighter-rouge">fmapDefault</code> and <code class="language-plaintext highlighter-rouge">foldMapDefault</code>.)</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">newtype</span> <span class="kt">Id</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Id</span> <span class="p">{</span> <span class="n">getId</span> <span class="o">::</span> <span class="n">a</span> <span class="p">}</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Functor</span> <span class="kt">Id</span> <span class="kr">where</span>
|
|||
|
<span class="n">fmap</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Id</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Id</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Applicative</span> <span class="kt">Id</span> <span class="kr">where</span>
|
|||
|
<span class="n">pure</span> <span class="n">x</span> <span class="o">=</span> <span class="kt">Id</span> <span class="n">x</span>
|
|||
|
<span class="p">(</span><span class="kt">Id</span> <span class="n">f</span><span class="p">)</span> <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="kt">Id</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Id</span> <span class="p">(</span><span class="n">f</span> <span class="n">x</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">fmapDefault</span> <span class="o">::</span> <span class="kt">Traversable</span> <span class="n">t</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">b</span>
|
|||
|
<span class="n">fmapDefault</span> <span class="n">f</span> <span class="o">=</span> <span class="n">getId</span> <span class="o">.</span> <span class="n">traverse</span> <span class="p">(</span><span class="kt">Id</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">foldMapDefault</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Monoid</span> <span class="n">m</span><span class="p">,</span> <span class="kt">Traversable</span> <span class="n">t</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span>
|
|||
|
<span class="n">foldMapDefault</span> <span class="n">f</span> <span class="o">=</span> <span class="n">getConst</span> <span class="o">.</span> <span class="n">traverse</span> <span class="p">(</span><span class="kt">Const</span> <span class="o">.</span> <span class="n">f</span><span class="p">)</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
|
|||
|
<p>See the <a href="https://www.stackage.org/haddock/lts-9.9/base-4.9.1.0/src/Data-Functor-Const.html#Const">Const</a> Functor’s definition for intuition.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Implement <code class="language-plaintext highlighter-rouge">Traversable</code> instances for <code class="language-plaintext highlighter-rouge">[]</code>, <code class="language-plaintext highlighter-rouge">Maybe</code>, <code class="language-plaintext highlighter-rouge">((,) a)</code>, and <code class="language-plaintext highlighter-rouge">Either a</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="kt">Traversable</span> <span class="kt">[]</span> <span class="kr">where</span>
|
|||
|
<span class="n">traverse</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">[</span><span class="n">b</span><span class="p">]</span>
|
|||
|
<span class="n">traverse</span> <span class="kr">_</span> <span class="kt">[]</span> <span class="o">=</span> <span class="n">pure</span> <span class="kt">[]</span>
|
|||
|
<span class="n">traverse</span> <span class="n">f</span> <span class="p">(</span><span class="n">x</span><span class="o">:</span><span class="n">xs</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="o">:</span><span class="p">)</span> <span class="o">&lt;$&gt;</span> <span class="n">f</span> <span class="n">x</span> <span class="o">&lt;*&gt;</span> <span class="kt">Main</span><span class="o">.</span><span class="n">traverse</span> <span class="n">f</span> <span class="n">xs</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Traversable</span> <span class="kt">Maybe</span> <span class="kr">where</span>
|
|||
|
<span class="n">traverse</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Maybe</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">traverse</span> <span class="kr">_</span> <span class="kt">Nothing</span> <span class="o">=</span> <span class="n">pure</span> <span class="kt">Nothing</span>
|
|||
|
<span class="n">traverse</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Just</span> <span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Just</span> <span class="o">&lt;$&gt;</span> <span class="n">f</span> <span class="n">x</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Traversable</span> <span class="p">((,)</span> <span class="n">c</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">traverse</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">traverse</span> <span class="n">f</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="p">(,)</span> <span class="n">c</span> <span class="o">&lt;$&gt;</span> <span class="n">f</span> <span class="n">a</span>
|
|||
|
|
|||
|
<span class="kr">instance</span> <span class="kt">Traversable</span> <span class="p">(</span><span class="kt">Either</span> <span class="n">c</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">traverse</span> <span class="o">::</span> <span class="kt">Applicative</span> <span class="n">f</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Either</span> <span class="n">c</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Either</span> <span class="n">c</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="n">traverse</span> <span class="kr">_</span> <span class="p">(</span><span class="kt">Left</span> <span class="n">c</span><span class="p">)</span> <span class="o">=</span> <span class="n">pure</span> <span class="p">(</span><span class="kt">Left</span> <span class="n">c</span><span class="p">)</span>
|
|||
|
<span class="n">traverse</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Right</span> <span class="n">a</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Right</span> <span class="o">&lt;$&gt;</span> <span class="n">f</span> <span class="n">a</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Explain why <code class="language-plaintext highlighter-rouge">Set</code> is <code class="language-plaintext highlighter-rouge">Foldable</code> but not <code class="language-plaintext highlighter-rouge">Traversable</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<p>First, in terms of laws, <code class="language-plaintext highlighter-rouge">Set</code> is not a <code class="language-plaintext highlighter-rouge">Functor</code>, thus it cannot be made into a <code class="language-plaintext highlighter-rouge">Traversable</code> instance, since <code class="language-plaintext highlighter-rouge">Traversable</code> instances require <code class="language-plaintext highlighter-rouge">Functor</code> superclasses.</p>
|
|||
|
|
|||
|
<p>Second, on an intuitive level: In <code class="language-plaintext highlighter-rouge">Foldable</code>, the goal is not to keep the shape/structure of the original container, we are trying to reduce the container into some value, and the shape of the final result doesn’t matter, but in <code class="language-plaintext highlighter-rouge">Traversable</code>, we ought to keep the structure of the final result, but we can’t guarantee this while using <code class="language-plaintext highlighter-rouge">Set</code>s, because we can define some transformation <code class="language-plaintext highlighter-rouge">f :: Set a -&gt; Set a</code> which reduces the length of the <code class="language-plaintext highlighter-rouge">Set</code>.</p>
|
|||
|
|
|||
|
<p>See <a href="https://stackoverflow.com/questions/35857733/foldable-vs-traversable">Foldable vs. Traversable</a> and <a href="https://stackoverflow.com/questions/19177125/sets-functors-and-eq-confusion">Sets, Functors and Eq confusion</a>. and <a href="https://wiki.haskell.org/Foldable_and_Traversable">Foldable and Traversable</a> for more details.</p>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Show that <code class="language-plaintext highlighter-rouge">Traversable</code> functors compose: that is, implement an instance for <code class="language-plaintext highlighter-rouge">Traversable (Compose f g)</code> given <code class="language-plaintext highlighter-rouge">Traversable</code> instances for <code class="language-plaintext highlighter-rouge">f</code> and <code class="language-plaintext highlighter-rouge">g</code>.</p>
|
|||
|
|
|||
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
|||
|
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kr">instance</span> <span class="p">(</span><span class="kt">Traversable</span> <span class="n">f</span><span class="p">,</span> <span class="kt">Traversable</span> <span class="n">g</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="kt">Traversable</span> <span class="p">(</span><span class="kt">Compose</span> <span class="n">f</span> <span class="n">g</span><span class="p">)</span> <span class="kr">where</span>
|
|||
|
<span class="n">traverse</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Applicative</span> <span class="n">f</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Compose</span> <span class="n">g</span> <span class="n">h</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Compose</span> <span class="n">g</span> <span class="n">h</span> <span class="n">b</span><span class="p">)</span>
|
|||
|
<span class="n">traverse</span> <span class="n">f</span> <span class="p">(</span><span class="kt">Compose</span> <span class="n">t</span><span class="p">)</span> <span class="o">=</span> <span class="kt">Compose</span> <span class="o">&lt;$&gt;</span> <span class="n">traverse</span> <span class="p">(</span><span class="n">traverse</span> <span class="n">f</span><span class="p">)</span> <span class="n">t</span>
|
|||
|
</code></pre></div> </div>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
</description>
|
|||
|
<pubDate>Wed, 27 Sep 2017 00:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/typoclassopedia-exercise-solutions/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/typoclassopedia-exercise-solutions/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>programming</category>
|
|||
|
|
|||
|
<category>math</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>DIY Cardboard Kindle Stand (for bed)</title>
|
|||
|
<description><p><img src="/img/kindle-stand/1.jpg" alt="a view of the stand + kindle" /></p>
|
|||
|
|
|||
|
<p>I’ve had a Kindle for more than a year now, but I’ve only recently started to read books on it frequently, I used to read paperworks before that, and I still do sometimes prefer paperbooks if available. Anyways, my Kindle has helped me to fall asleep without struggling with all my thoughts, all I have to do is read until I fall asleep, so in a way, it has also been a remedy for my insomnia.</p>
|
|||
|
|
|||
|
<p>Now to read the Kindle in bed, you would have to hold it using your hands or buy a stand or make one, motivated by <a href="https://blog.xkcd.com/2009/04/13/the-pursuit-of-laziness/">The Pursuit of Laziness</a> I set to create mine, but I didn’t use a piece of steel, instead I used a single box of cardboard I had in home to create one in minutes. :D</p>
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
<p>It’s too easy to need much of an instruction, a few pictures and some explanation will do:</p>
|
|||
|
|
|||
|
<p><img src="/img/kindle-stand/0.jpg" alt="a view of the stand without kindle" /></p>
|
|||
|
|
|||
|
<p>So this part shows a simple piece of cardboard cut using scissors on the front, with the sides taped to the bottom (actually if your piece of cardboard is a box, it might already be taped in that way, mine was).</p>
|
|||
|
|
|||
|
<p><img src="/img/kindle-stand/2.jpg" alt="a view of the stand's back side" /></p>
|
|||
|
|
|||
|
<p>On the back, there is another piece of cardboard (I took the opening of it which already had a notch line, and the size fit perfectly). I used a stapler to to attach the two sides toghether, and that’s it!</p>
|
|||
|
|
|||
|
<p>I tried it last night to make sure it’s convenient before posting here, and I tell you, it is totally comfortable and much better than holding with a hand.</p>
|
|||
|
</description>
|
|||
|
<pubDate>Sun, 24 Sep 2017 00:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/diy-cardboard-kindle-stand/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/diy-cardboard-kindle-stand/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>life</category>
|
|||
|
|
|||
|
<category>diy</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Difference between Travis CI tests: PR and Push</title>
|
|||
|
<description><p>I just want to leave this here as I often tend to look it up myself and the first time it was not as easy to figure out.</p>
|
|||
|
|
|||
|
<p>When using Travis CI along with GitHub (or other git integrations), Travis runs two tests: <code>pr</code> and <code>push</code>.</p>
|
|||
|
|
|||
|
<p><img src="/img/travis-ci-pr-push-github.jpg" alt="travis-pr-push-github" /></p>
|
|||
|
|
|||
|
<p>Most of the time you see both tests passing and you do not have to even wonder how they are different, but it has
|
|||
|
happened to me that one of the tests fails while the other passes and I started to wonder why.</p>
|
|||
|
|
|||
|
<h3 id="pr">pr</h3>
|
|||
|
<p>The <code>pr</code> test is a test run on the result of a merge between the pull-request branch and the main branch.
|
|||
|
As an example, let’s say your pull-request’s branch is called <code>fix-user-auth</code> and your main branch is <code>master</code>,
|
|||
|
in this case, <code>pr</code> merges <code>fix-user-auth</code> into <code>master</code> and then runs the tests on the result of the merge.</p>
|
|||
|
|
|||
|
<h3 id="push">push</h3>
|
|||
|
<p>On the other hand, <code>push</code> is run on the pull-request branch itself, without merging. So in our example above, Travis would checkout to <code>fix-user-auth</code> and run the tests.</p>
|
|||
|
|
|||
|
<h3 id="a-case-of-difference">A case of difference</h3>
|
|||
|
|
|||
|
<p>A case in which this difference might be more apparent is when your pull-request is based on a branch other than <code>master</code>, and some changes that your pull-request depends on are missing from <code>master</code>, in this case the <code>push</code> test may pass, but the <code>pr</code> test will fail.</p>
|
|||
|
|
|||
|
</description>
|
|||
|
<pubDate>Sat, 09 Sep 2017 00:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/travis-ci-pr-push/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/travis-ci-pr-push/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>programming</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Primitive Living Lessons Learned, Episode 0</title>
|
|||
|
<description><p><img src="/img/primitive-living-0.jpg" alt="general view of the forest" /></p>
|
|||
|
|
|||
|
<p>So I just went on my first primitive living practice trip in the woods, alone, with only a pocket knife.</p>
|
|||
|
|
|||
|
<p>I decided I’m going to share the lessons I’ve learned in each trip as they are certainly going to be useful if you want to practice primitive living, I would find these useful if I could find them anywhere. I spend a lot of time reading and watching primitive living guides and experience reports, but they are never exhaustive, and this series is not meant to be exhaustive either.</p>
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
<p>Here we go:</p>
|
|||
|
|
|||
|
<h1 id="what-i-did-know">What I did know</h1>
|
|||
|
|
|||
|
<p>I spent a lot of time studying about edible wild plants, how to butcher and cook different kinds of animals and insects. I also had practiced fire by friction and read a lot and watched videos about theory of making cordages, making a bow-drill and so on. I also knew and had already built shelters for the night. So you can assume I had a basic, broad understanding of the necessary skills, but experience? Not so much.</p>
|
|||
|
|
|||
|
<h1 id="setup">Setup</h1>
|
|||
|
|
|||
|
<p>I had a pocket knife, a Garmin GPS and a pocket first aid kid, I would expect something to go wrong along the way, so I thought I want to be safe, but not comfortable, that’s why I brought emergency necessities, but not any comfort tools and materials. I also had a canned tuna for my first breakfast, but nothing more.</p>
|
|||
|
|
|||
|
<p>Now for what is worth, I’m going in around summer’s end, September 5th, in a forest in northern Iran, Mazandaran Province. The forest starts from foothills, covering a few mounts from both sides, so it’s pretty large but also mountaneous, so I it’s hard to move in the forest.</p>
|
|||
|
|
|||
|
<h1 id="arrival-first-night">Arrival: First Night</h1>
|
|||
|
|
|||
|
<p>So I arrived at the entrace of the forest at night, it was already dark and I couldn’t build a shelter or do much, I just slept on the open ground, it was my first night in the woods alone. I was quite scared at first, lots of cracks and movements in bushes by unknown creatures, but after a few hours I figured out all these creatures are small ones that can’t be harmful to me. A few hours before dawn it got bitter cold, and I woke up, unable to go back to sleep. The first night was not the best, but could be worse.</p>
|
|||
|
|
|||
|
<h1 id="first-day">First Day</h1>
|
|||
|
|
|||
|
<p>I woke early at dawn and started moving into the forest, looking for a place to build my shelter in. I decided I’m going to follow these steps:</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Build a shelter</li>
|
|||
|
<li>Find water source</li>
|
|||
|
<li>Build a fire</li>
|
|||
|
<li>Find food</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<p>But as was expected, it didn’t go according to the plan.</p>
|
|||
|
|
|||
|
<p><img src="/img/primitive-living-0-shelter.jpg" alt="my shelter, done" /></p>
|
|||
|
|
|||
|
<h2 id="shelter">Shelter</h2>
|
|||
|
|
|||
|
<p>I found a nice place to stay which had a stream passing by, the stream was running and from what I knew about the area, the water was safe to drink, so water was no longer an issue. I started building my shelter, got the base wooden structure down first, but there was a catch: I couldn’t find any dry debris to put on top or inside. Last time I had built the same shelter it was autumn’s end/early spring, so there were lots of dry, fallen leaves on the ground; But this time it’s in the summer and there very few, scattered dry leaves on the ground, uncollectable.</p>
|
|||
|
|
|||
|
<p>I decided I’m going with leaves of a small tree I had found nearby which seemed to be abundant around the area and the branches had lots of close leaves on them, looked like a good choice, but it was green. I didn’t find out what I was doing wrong until I tried to sleep at night. The green leaves attracted lots of flies and insects and all sorts of annoying disturbances, and the smell wasn’t helping either. I had to endure the insects throughout the night, because sleeping outside the shelter was a no-go, the dirt beneath was too cold. I hadn’t put as much leaves on the ground, and the leaves were green (which also means they take more heat away), but still, it was much better than sleeping directly on the ground.</p>
|
|||
|
|
|||
|
<p>What I learned was, <strong>do not use green leaves for covering your shelter</strong>. This rule applies to small shelters in which you are close to the covering, as well as the leaves you use as bedding. I’ve seen people using green leaves for covering big shelters which have a high ceiling, though I don’t have any experience with those myself.</p>
|
|||
|
|
|||
|
<p><img src="/img/primitive-living-0-friction-fire.jpg" alt="friction fire tries" /></p>
|
|||
|
|
|||
|
<h2 id="friction-fire">Friction Fire</h2>
|
|||
|
|
|||
|
<p>The most important part of primitive living is fire, without fire you can’t cook, you can’t stay warm and you can’t defy nocturnal predators. You also can’t repel insects. You can’t make a torch, so there goes an infinite list of fire applications that you will miss.</p>
|
|||
|
|
|||
|
<p>I knew the theory of friction fire in and out, how and why it works, but what I had missed was, <strong>you are going to be in <em>real trouble</em> if you can’t find softwood</strong>. To my surprise, searching portions of the forest, I couldn’t find any softwood tree. Oaks were everywhere, as well as quite some other species of trees, but all of them were hardwood.</p>
|
|||
|
|
|||
|
<p>I tried different combinations of the softer woods I could find, but none of them resulted in an ember, I got smoke with one combination, but that was it. After about 5-6 hours of trying, I got real tired and gave up. By the way, I tried hand-drills, I couldn’t succeed with bow-drills as I couldn’t find suitable cordage, I tried with a promising bark that was pretty strong, but it would break as soon as I put some pressure on it, It’s also possible that I might’ve gone wrong in making the bow itself, so it would cause the breakage.</p>
|
|||
|
|
|||
|
<p>So the lesson was <strong>make sure the material you are going to practice with is available in your practice area</strong>, had I known there were no softwood in that particular forest, I would change my destination and probably succeed somewhere else. Sure, a professional survivalist must be able to start a fire in almost all situations, but this is practice and you have to start with easier steps.</p>
|
|||
|
|
|||
|
<p>I ended up shaking for 2 hours before the dawn, not a pleasant experience at all. :D</p>
|
|||
|
|
|||
|
<h2 id="food">Food</h2>
|
|||
|
|
|||
|
<p>The difficulties didn’t end there, without a fire, my only hope for food was specific edible plants which can be eaten raw, or fruits. Unlucky as I was, I couldn’t find a single fruit-bearing tree in the forest (I found quite a few fruit-bearing trees along the roads and paths to the forest, but not inside the forest itself), and I also couldn’t find any of the other edible plants (I was mostly looking for the onion family) that I knew of.</p>
|
|||
|
|
|||
|
<p>One of the greatest complications when starting primitive living practice anywhere other than the U.S. is that <strong>almost all guides and materials on the topic are from, and for Northern America</strong>. <a href="https://www.amazon.com/Edible-Wild-Plants-Falcon-Field/dp/0762774215">The Falcon Guide to Edible Wild Plants</a> that I read is all about northern american plants. I knew it, but it’s also the case that the Northern Hemisphere of the Earth have more common of an ecology, so most of the plants found in Northern America can also be found in places like Iran, but they have their differences. Most of the tips and tricks provided in different resources are for Northern American forests, which do not always work in other places.</p>
|
|||
|
|
|||
|
<p>So all in all, I ended up not eating anything for the next 24 hours, until I got out of the forest.</p>
|
|||
|
|
|||
|
<h2 id="psychology">Psychology</h2>
|
|||
|
|
|||
|
<p>Apart from all the physical failures that I faced, which in turn caused frustration, I also had strong feelings of loneliness, boredom, and fear upon me. It was after failing to start a fire that I really felt the psychological burden on me. I had read about similar experiences, but believe me, the experience is hardly transmittable by words. A local rancher passing by the forest telling me about the leopard in the forest didn’t make things any easier.</p>
|
|||
|
|
|||
|
<p>The psychological pressure was above all other difficulties, at some point I was bursting into tears, but I couldn’t associate it with any one specific feeling, it was a mix of anger, loneliness and fear.</p>
|
|||
|
|
|||
|
<p>Anger and frustration because I couldn’t succeed in what I was trying to do. I also cut my finger at some point while carving the woods, so there was that.</p>
|
|||
|
|
|||
|
<p>Loneliness because I was all by myself and I had no company to talk to. You can really actually go insane, as seen in <a href="https://en.wikipedia.org/wiki/Cast_Away">Cast Away</a>, after prolonged sessions of loneliness in situations like that. Mine wasn’t long, it was only two days, but I still experienced the thought-fog, I couldn’t think straight.</p>
|
|||
|
|
|||
|
<p>Fear because I felt weak compared to the power of nature, my fear was doubled by the fact that I was alone. I felt like being in a place where everything seems to know what it is doing, but I don’t; I felt lost, not knowing what to do after my basic plans had failed.</p>
|
|||
|
|
|||
|
<p>Now I don’t know if there is much you can do about the psychological part of it, I think experience is the remedy, at least I felt how different it was between the nights, the first night, even though I wasn’t even <em>inside</em> the forest much, I was almost at the border of it, it was much more creepy because it was my first time, but the second night, I was in the forest and now I had a <em>leopard</em> in my mind pouncing on me, but I felt less fear and was more comfortable.</p>
|
|||
|
|
|||
|
<p>But in the end, what helped me was that <em>I knew I was going to face a huge mental challenge along the way</em>, so I was more prepared. I think it’s utterly important to be prepared for such psychological situations, knowing the reason behind your psychological challenges can help you overcome it to some extend.</p>
|
|||
|
|
|||
|
<h1 id="second-night">Second Night</h1>
|
|||
|
|
|||
|
<p>The second and last night was not all that much interesting, but it was damn sure cold and hard. At first I had to deal with the insects biting me everywhere and my feet scratching while trying to sleep in the shelter that I had wrongly built. After getting over that one and sleeping for what seemed to be ~2 hours, I woke up and felt the air temperature decreasing. I still got to sleep in intervals of 30 minutes until I woke up at around ~4 AM and my whole body was shaking. I couldn’t do much, all I did was gather the leaves underneath a little closer and more dense, and crunch my body into a ball so I felt just a little warmer, but still shaking. It took ages for the last two and a half hours to pass until dawn. At dawn I got up quickly and walked around a little to warm myself up, and then waited until I could barely see my surroundings, then I started walking out of the forest.</p>
|
|||
|
|
|||
|
<p>Initially I had decided to stay for longer, but the weather forecast had predicted a heavy rain and storm for the next night, there was no way I could withstand that. :D</p>
|
|||
|
|
|||
|
<h1 id="bottom-line">Bottom Line</h1>
|
|||
|
|
|||
|
<p>It was a hard trip, I lost about 2kg (4lb) weight, but all in all the experience was a good one, I certainly learned a lot and I’m not going to make the same mistakes again. I should definitly practice more and keep working on my skills.</p>
|
|||
|
|
|||
|
<p>If you are looking forward to practicing primitive living, please make sure you are safe and start small.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Success is going from failure to failure without losing your enthusiasm. —Winston Churchill</p>
|
|||
|
</blockquote>
|
|||
|
</description>
|
|||
|
<pubDate>Thu, 07 Sep 2017 00:00:00 +0100</pubDate>
|
|||
|
<link>http://localhost:4000/primitive-living-lessons-0/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/primitive-living-lessons-0/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>life</category>
|
|||
|
|
|||
|
<category>primitive-living</category>
|
|||
|
|
|||
|
<category>travel</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
|
|||
|
<item>
|
|||
|
<title>Don't chase: Become the good one</title>
|
|||
|
<description><p>When it comes to relationships, most (unsuccessful) people are <em>chasing</em> the good ones.
|
|||
|
They spend time trying to find their dream partner, the perfect match, but hey, do you qualify
|
|||
|
as the dream partner of your dream partner? You fantasize about your dream partner, but have you ever
|
|||
|
thought what kind of partner does he/she dream of?</p>
|
|||
|
|
|||
|
<p><img src="/img/angel.jpg" alt="I want an angel with..." />
|
|||
|
<span class="image-caption">I want an angel with…</span></p>
|
|||
|
|
|||
|
<!--more-->
|
|||
|
|
|||
|
<p>It seems to be pretty acceptable in the society to start <em>looking</em> for a <em>good</em> partner once you
|
|||
|
reach a certain age (depending on the country), and that’s when people start defining for themselves what
|
|||
|
a <em>good</em> partner means. What do they want out of a relationship? Well, most beginners just want sex, that’s one thing,
|
|||
|
but I’m talking about real, intimate relationships. The definition usually goes like this:</p>
|
|||
|
|
|||
|
<p>I want him/her to have</p>
|
|||
|
<ul>
|
|||
|
<li>Money</li>
|
|||
|
<li>Body</li>
|
|||
|
<li>Sense of Humor</li>
|
|||
|
<li>Empathy</li>
|
|||
|
<li>…</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Alright fine, that’s a good and necessary step while thinking about a relationship.</p>
|
|||
|
|
|||
|
<p>Now there are two groups of people after this step, let’s call them Group A and Group B.</p>
|
|||
|
|
|||
|
<p>Group A’s next step is to start looking for partners, which usually follows by installing Tinder, OkCupid and a bunch of other
|
|||
|
dating apps, spending more time in the bar, etc. Well it makes sense to start looking for a partner at first glance, but people in Group A
|
|||
|
are missing an important point here, they defined what a <em>good partner</em> means in their dictionary of life, but they haven’t
|
|||
|
really looked into their <em>good partner</em>’s dictionary to see what he/she wants out of a relationship, because if you don’t qualify her requirements,
|
|||
|
it’s not a deal.</p>
|
|||
|
|
|||
|
<p>Now there is a sub-group of Group A, too, and it includes the people who faced with the question “am I what she dreams of?”, they
|
|||
|
try to cheat and modify their definition of a good partner, adding a line that goes “Loves me however I am”, sorry buddy, but what if I
|
|||
|
tell you she could add the same line to her dictionary? That’s not a deal, you want a good partner as you defined it, you have to be a good partner
|
|||
|
as she defines it.</p>
|
|||
|
|
|||
|
<p>On the other hand, Group B doesn’t follow the same path as Group A. Group B starts by trying to predict what his dream partner would want
|
|||
|
out of a relationship. Empathy? Loyalty? Knowledge? Body? They take a pen and a paper out and write a list of what they think their dream partner
|
|||
|
would want them to have, what would she want them to be, and they start working on those, and I bet it’s not going to be easy, knowledge doesn’t pop up
|
|||
|
after a good night’s sleep, you have to spend years reading books and learning to get it. A good body doesn’t <em>poof</em> out if you wish it to, you have
|
|||
|
to spend years being committed to exercise and eating well, and that’s not easy. After all, what you define as a good partner ain’t easy either, is it?</p>
|
|||
|
|
|||
|
<p>Now do you want your dream partner to fall for you the way you fall for her, without having to chase her with a net? Write down a list of
|
|||
|
qualifications you expect your dream partner to look for, and start working your ass off reaching them, and I tell you, you will have a much easier <em>next step</em> after this. You won’t have to chase girls hoping the 34th one doesn’t reject you because “she likes you however you are”.</p>
|
|||
|
|
|||
|
<p>If I know one thing about life, it’s the fact that you have to work your ass off in order to reach your dreams, dreams aren’t easy, and a deep, intimate relationship really is a dream.</p>
|
|||
|
</description>
|
|||
|
<pubDate>Sat, 04 Feb 2017 00:00:00 +0000</pubDate>
|
|||
|
<link>http://localhost:4000/dont-chase-become-the-good-one/</link>
|
|||
|
<guid isPermaLink="true">http://localhost:4000/dont-chase-become-the-good-one/</guid>
|
|||
|
|
|||
|
|
|||
|
<category>life</category>
|
|||
|
|
|||
|
</item>
|
|||
|
|
|||
|
</channel>
|
|||
|
</rss>
|