2022-08-24 14:52:32 +00:00
<!DOCTYPE html>
< html lang = 'en' >
< head >
< meta charset = 'UTF-8' / >
< meta name = 'viewport' content = 'width=device-width, initial-scale=1' / >
< title >
*-Morpisms – Home
< / title >
< meta property = 'og:description' content = 'Backup eines Blogposts eines Kommilitonen:' / >
< meta property = 'og:site_name' content = 'Home' / >
< meta property = 'og:image' content / >
< meta property = 'og:type' content = 'website' / >
< meta property = 'og:title' content = '*-Morpisms' / >
< base href = '/' / >
< link href = 'favicon.svg' rel = 'icon' / >
< script >
window.MathJax = {
startup: {
ready: () => {
MathJax.startup.defaultReady();
}
}
};
< / script >
< script async id = 'MathJax-script' src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js' > < / script >
<!-- mermaid.js --> < script src = 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js' > < / script >
< script >
mermaid.initialize({startOnLoad:false});
mermaid.init(undefined,document.querySelectorAll(".mermaid"));
< / script >
<!-- highlight.js -->
< link rel = 'stylesheet' href = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/hybrid.min.css' / >
< script src = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js' > < / script >
<!-- Include languages that Emanote itself uses -->
< script src = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/haskell.min.js' > < / script >
< script src = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/nix.min.js' > < / script >
< script > hljs . highlightAll ( ) ; < / script >
2022-08-25 04:18:18 +00:00
< link href = 'tailwind.css?instanceId=ecadcd50-ecaf-4d6e-98ea-7932c3b3d351' rel = 'stylesheet' type = 'text/css' / >
2022-08-24 14:52:32 +00:00
<!-- Heist error element -->
< style >
strong.error {
color: lightcoral;
font-size: 90%;
font-family: monospace;
}
< / style >
<!-- What goes in this file will appear on near the end of <head> --> < link rel = 'preload' href = '_emanote-static/fonts/Maven_Pro/MavenPro-VariableFont_wght.ttf' as = 'font' type = 'font/ttf' crossorigin / >
< style >
@font-face {
font-family: 'MavenPro';
/* FIXME: This ought to be: ${ema:emanoteStaticLayerUrl}/fonts/Maven_Pro/MavenPro-VariableFont_wght.ttf */
src: url(_emanote-static/fonts/Maven_Pro/MavenPro-VariableFont_wght.ttf) format("truetype");
font-display: swap;
}
body {
font-family: 'MavenPro', sans-serif;
/* font-variation-settings: 'wght'300; */
}
a.mavenLinkBold {
font-variation-settings: 'wght'500;
}
strong {
font-variation-settings: 'wght'500;
}
h1,
h2,
h3,
h4,
h5,
h6,
header,
.header-font {
font-family: 'MavenPro', sans-serif;
}
< / style >
< link rel = 'stylesheet' href = '_emanote-static/inverted-tree.css' / >
< link rel = 'stylesheet' href = 'https://files.stork-search.net/releases/v1.5.0/flat.css' / >
<!-- Custom Stork - search styling for Emanote -->
< style >
#stork-search-container {
z-index: 1000;
background-color: rgb(15 23 42/.8);
}
.stork-overflow-hidden-important {
overflow: hidden !important;
}
< / style >
< script src = 'https://files.stork-search.net/releases/v1.5.0/stork.js' > < / script >
< script data-emanote-base-url = '/' >
window.emanote = {};
window.emanote.stork = {
searchShown: false,
toggleSearch: function () {
document.getElementById('stork-search-container').classList.toggle('hidden');
window.emanote.stork.searchShown = document.body.classList.toggle('stork-overflow-hidden-important');
if (window.emanote.stork.searchShown) {
document.getElementById('stork-search-input').focus();
}
},
clearSearch: function () {
document.getElementById('stork-search-container').classList.add('hidden');
document.body.classList.remove('stork-overflow-hidden-important');
window.emanote.stork.searchShown = false;
},
init: function () {
const indexName = 'emanote-search'; // used to match input[data-stork] attribute value
const baseUrl = document.currentScript.getAttribute('data-emanote-base-url') || '/';
const indexUrl = baseUrl + '-/stork.st';
if (document.readyState !== 'complete') {
window.addEventListener('load', function () {
stork.register(indexName, indexUrl);
});
document.addEventListener('keydown', event => {
if (window.emanote.stork.searchShown & & event.key === 'Escape') {
window.emanote.stork.clearSearch();
event.preventDefault();
} else if ((event.key == 'k' || event.key == 'K') & & (event.ctrlKey || event.metaKey)) {
window.emanote.stork.toggleSearch();
event.preventDefault();
}
});
} else {
// Override existing on Ema's hot-reload
stork.register(indexName, indexUrl, { forceOverwrite: true });
}
}
};
window.emanote.stork.init();
< / script >
< / head >
<!-- DoNotFormat -->
<!-- DoNotFormat -->
< body class = 'bg-gray-400 overflow-y-scroll' >
< div class = 'container mx-auto' >
< nav id = 'breadcrumbs' class = 'w-full text-gray-700 md:hidden' >
< div class = 'flex justify-left' >
< div class = 'w-full px-2 py-2 bg-gray-50' >
< ul class = 'flex flex-wrap text-lg' >
< li class = 'inline-flex items-center' >
< img style = 'width: 1rem;' src = 'favicon.svg' / >
< / li >
< li class = 'inline-flex items-center' >
< a class = 'px-1 font-bold' href = '' >
Home
< / a >
< svg fill = 'currentColor' viewBox = '0 0 20 20' class = 'w-auto h-5 text-gray-400' >
< path fill-rule = 'evenodd' d = 'M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z' clip-rule = 'evenodd' > < / path >
< / svg >
< / li >
< li class = 'inline-flex items-center' >
< a class = 'px-1 font-bold' href = 'Haskell' >
Haskell
< / a >
< svg fill = 'currentColor' viewBox = '0 0 20 20' class = 'w-auto h-5 text-gray-400' >
< path fill-rule = 'evenodd' d = 'M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z' clip-rule = 'evenodd' > < / path >
< / svg >
< / li >
< li class = 'inline-flex items-center' >
< a class = 'px-1 font-bold' href = 'Haskell/Code%20Snippets' >
Code-Snippets
< / a >
< svg fill = 'currentColor' viewBox = '0 0 20 20' class = 'w-auto h-5 text-gray-400' >
< path fill-rule = 'evenodd' d = 'M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z' clip-rule = 'evenodd' > < / path >
< / svg >
< / li >
< / ul >
< / div >
< button class = 'inline px-2 py-1 bg-gray-50 outline-none cursor-pointer focus:outline-none' title = 'Search (Ctrl+K)' type = 'button' onclick = 'window.emanote.stork.toggleSearch()' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' style = 'width: 1rem;' class = 'hover:text-purple-700' f
2022-08-24 14:52:32 +00:00
fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'>
< path stroke-linecap = 'round' stroke-linejoin = 'round' d = 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' > < / path >
< / svg >
< / button >
2022-08-25 04:18:18 +00:00
< button class = 'inline px-2 py-1 text-white bg-purple-600 outline-none cursor-pointer focus:outline-none' title = 'Toggle sidebar' type = 'button' onclick = "toggleHidden('sidebar')" >
2022-08-24 14:52:32 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4' fill = 'none' viewBox = '0 0 24 24' stroke = 'currentColor' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M4 6h16M4 12h16M4 18h16' > < / path >
< / svg >
< / button >
< script >
function toggleHidden(elemId) {
document.getElementById(elemId).classList.toggle("hidden");
}
< / script >
< / div >
< / nav >
< div id = 'container' class = 'flex flex-nowrap flex-col md:flex-row bg-gray-50 md:mt-8 md:shadow-2xl md:mb-8' >
<!-- Sidebar column -->
< nav id = 'sidebar' class = 'flex-shrink hidden leading-relaxed md:block md:sticky md:top-0 md:h-full md:w-48 xl:w-64' >
< div class = 'px-2 py-2 text-gray-800' >
< div id = 'indexing-links' class = 'flex flex-row float-right p-2 space-x-2 text-gray-500' >
< a href = '-/tags' title = 'View tags' >
2022-08-25 04:18:18 +00:00
< svg style = 'width: 1rem;' class = 'hover:text-purple-700' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z' >
< / path >
< / svg >
< / a >
< a href = '-/all' title = 'Expand full tree' >
2022-08-25 04:18:18 +00:00
< svg style = 'width: 1rem;' class = 'hover:text-purple-700' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4' >
< / path >
< / svg >
< / a >
< a title = 'Search (Ctrl+K)' class = 'cursor-pointer' onclick = 'window.emanote.stork.toggleSearch()' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' style = 'width: 1rem;' class = 'hover:text-purple-700' f
2022-08-24 14:52:32 +00:00
fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'>
< path stroke-linecap = 'round' stroke-linejoin = 'round' d = 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' > < / path >
< / svg >
< / a >
< / div >
< div id = 'site-logo' class = 'pl-2' >
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< a href = '' title = 'Go to Home' >
<!-- The style width attribute here is to prevent huge
icon from displaying at those rare occasions when Tailwind
hasn't kicked in immediately on page load
-->
< img style = 'width: 1rem;' class = 'transition transform hover:scale-110 hover:opacity-80' src = 'favicon.svg' / >
< / a >
< a class = 'font-bold truncate' title = 'Go to Home' href = '' >
Home
< / a >
< / div >
< / div >
<!-- Variable bindings for this tree -->
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-500' viewBox = '0 0 20 20' fill = 'currentColor' >
< path d = 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z' > < / path >
2022-08-24 14:52:32 +00:00
< / svg >
2022-08-25 04:18:18 +00:00
< a class = 'hover:underline truncate' title = 'About' href = 'About' >
About
2022-08-24 14:52:32 +00:00
< / a >
2022-08-25 04:18:18 +00:00
< span class = 'text-gray-300' title = '3 children inside' >
3
< / span >
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-500' viewBox = '0 0 20 20' fill = 'currentColor' >
< path d = 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z' > < / path >
2022-08-24 14:52:32 +00:00
< / svg >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
2022-08-25 04:18:18 +00:00
< a class = 'hover:underline truncate' title = 'Android' href = 'Android' >
2022-08-24 14:52:32 +00:00
Android
< / a >
2022-08-25 04:18:18 +00:00
< span class = 'text-gray-300' title = '1 children inside' >
1
< / span >
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-700' viewBox = '0 0 20 20' fill = 'currentColor' >
< path fill-rule = 'evenodd' d = 'M2 6a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1H8a3 3 0 00-3 3v1.5a1.5 1.5 0 01-3 0V6z' clip-rule = 'evenodd' > < / path >
< path d = 'M6 12a2 2 0 012-2h8a2 2 0 012 2v2a2 2 0 01-2 2H2h2a2 2 0 002-2v-2z' > < / path >
< / svg >
< a class = 'font-bold hover:underline truncate' title = 'Haskell' href = 'Haskell' >
Haskell
< / a >
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
<!-- Variable bindings for this tree -->
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-700' viewBox = '0 0 20 20' fill = 'currentColor' >
< path fill-rule = 'evenodd' d = 'M2 6a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1H8a3 3 0 00-3 3v1.5a1.5 1.5 0 01-3 0V6z' clip-rule = 'evenodd' > < / path >
< path d = 'M6 12a2 2 0 012-2h8a2 2 0 012 2v2a2 2 0 01-2 2H2h2a2 2 0 002-2v-2z' > < / path >
< / svg >
< a class = 'font-bold hover:underline truncate' title = 'Code-Snippets' href = 'Haskell/Code%20Snippets' >
Code-Snippets
< / a >
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
<!-- Variable bindings for this tree -->
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z' >
< / path >
< / svg >
2022-08-25 04:18:18 +00:00
< a class = 'font-bold text-purple-600 hover:underline truncate' title = '*-Morpisms' href = 'Haskell/Code%20Snippets/Morphisms' >
2022-08-24 14:52:32 +00:00
*-Morpisms
< / a >
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z' >
< / path >
< / svg >
< a class = 'hover:underline truncate' title = 'Monoid? Da war doch was…' href = 'Haskell/Code%20Snippets/Monoid' >
Monoid? Da war doch was…
< / a >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z' >
< / path >
< / svg >
< a class = 'hover:underline truncate' title = 'Fortgeschrittene funktionale Programmierung in Haskell' href = 'Haskell/FFPiH' >
Fortgeschrittene funktionale Programmierung in Haskell
< / a >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z' >
< / path >
< / svg >
< a class = 'hover:underline truncate' title = 'Lenses' href = 'Haskell/Lenses' >
Lenses
< / a >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z' >
< / path >
< / svg >
< a class = 'hover:underline truncate' title = 'Talks und Posts zu Haskell' href = 'Haskell/Advantages' >
Talks und Posts zu Haskell
< / a >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 03:26:25 +00:00
2022-08-24 14:52:32 +00:00
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-500' viewBox = '0 0 20 20' fill = 'currentColor' >
< path d = 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z' > < / path >
2022-08-24 14:52:32 +00:00
< / svg >
2022-08-25 04:18:18 +00:00
< a class = 'hover:underline truncate' title = 'Webapp-Development in Haskell' href = 'Haskell/Webapp-Example' >
Webapp-Development in Haskell
2022-08-25 03:26:25 +00:00
< / a >
2022-08-25 04:18:18 +00:00
< span class = 'text-gray-300' title = '2 children inside' >
2
< / span >
2022-08-25 03:26:25 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
< svg class = 'w-4 h-4 flex-shrink-0 inline' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z' >
< / path >
< / svg >
< a class = 'hover:underline truncate' title = 'Logik für Dummies' href = 'Logik' >
Logik für Dummies
< / a >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-500' viewBox = '0 0 20 20' fill = 'currentColor' >
< path d = 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z' > < / path >
2022-08-24 14:52:32 +00:00
< / svg >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
2022-08-25 04:18:18 +00:00
< a class = 'hover:underline truncate' title = 'Uni' href = 'Uni' >
2022-08-24 14:52:32 +00:00
Uni
< / a >
2022-08-25 04:18:18 +00:00
< span class = 'text-gray-300' title = '2 children inside' >
2
< / span >
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
<!-- Variable bindings for this tree -->
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
<!-- Rendering of this tree -->
< div class = 'pl-2' >
<!-- Node's rootLabel -->
< div class = 'flex items-center my-2 space-x-2 justify-left' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-4 h-4 flex-shrink-0 inline text-gray-500' viewBox = '0 0 20 20' fill = 'currentColor' >
< path d = 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z' > < / path >
2022-08-24 14:52:32 +00:00
< / svg >
2022-08-25 04:18:18 +00:00
2022-08-24 14:52:32 +00:00
2022-08-25 04:18:18 +00:00
< a class = 'hover:underline truncate' title = 'Unix' href = 'Unix' >
2022-08-24 14:52:32 +00:00
Unix
< / a >
2022-08-25 04:18:18 +00:00
< span class = 'text-gray-300' title = '1 children inside' >
1
< / span >
2022-08-24 14:52:32 +00:00
< / div >
<!-- Node's children forest, displayed only on active trees
TODO: Use < details > to toggle visibility?
-->
< / div >
< / div >
< / nav >
<!-- Main body column -->
< div class = 'flex-1 w-full overflow-x-auto bg-white' >
< main class = 'px-4 py-4' >
<!-- DoNotFormat -->
<!-- DoNotFormat -->
< nav id = 'uptree' class = 'flipped tree' style = 'transform-origin: 50%;' >
< ul class = 'root' >
< li >
< ul >
< li >
< div class = 'text-gray-900 forest-link' >
< a href = 'Haskell/Advantages' >
Talks und Posts zu Haskell
< / a >
< / div >
< ul >
< li >
< div class = 'text-gray-900 forest-link' >
< a href = 'Haskell' >
Haskell
< / a >
< / div >
< ul >
< li >
< div class = 'text-gray-900 forest-link' >
< a href = '' >
Home
< / a >
< / div >
< / li >
< / ul >
< / li >
< / ul >
< / li >
< li >
< div class = 'text-gray-900 forest-link' >
< a href = 'Haskell/Code%20Snippets' >
Code-Snippets
< / a >
< / div >
< / li >
< / ul >
< / li >
< / ul >
< / nav >
2022-08-25 04:18:18 +00:00
< h1 class = 'flex items-end justify-center mb-4 p-3 bg-purple-100 text-5xl font-extrabold text-black rounded' >
2022-08-24 14:52:32 +00:00
< a class = 'z-40 tracking-tighter ' >
*-Morpisms
< / a >
< / h1 >
< article class = 'overflow-auto' >
<!-- What goes in this file will appear on top of note body -->
< p class = 'mb-3' >
< strong > Backup eines Blogposts eines Kommilitonen:< / strong >
< / p >
< p class = 'mb-3' >
This weekend I spend some time on Morphisms.
< / p >
< p class = 'mb-3' >
Knowing that this might sound daunting to many dabbling Haskellers (like I am), I decided to write a real short MergeSort hylomorphism quickstarter.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
For those who need a refresher: MergeSort works by creating a balanced binary tree from the input list and directly collapsing it back into itself while treating the children as sorted lists and merging these with an O(n) algorithm.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
First the usual prelude:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > {-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Functor.Foldable
import Data.List (splitAt, unfoldr)< / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
We will use a binary tree like this. Note that there is no explicit recursion used, but < code class = 'py-0.5 px-0.5 bg-gray-100' > NodeF< / code > has two < em > holes< / em > . These will eventually filled later.
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > data TreeF c f = EmptyF | LeafF c | NodeF f f
deriving (Eq, Show, Functor)< / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Aside: We could use this as a < em > normal< / em > binary tree by wrapping it in < code class = 'py-0.5 px-0.5 bg-gray-100' > Fix< / code > : < code class = 'py-0.5 px-0.5 bg-gray-100' > type Tree a = Fix (TreeF a)< / code > But this would require us to write our tree like < code class = 'py-0.5 px-0.5 bg-gray-100' > Fix (NodeF (Fix (LeafF 'l')) (Fix (LeafF 'r')))< / code > which would get tedious fast. Luckily Edward build a much better way to do this into < em > recursion-schemes< / em > . I will touch on this later.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Without further ado we start to write a Coalgebra, which in my book is just a scary name for “function that is used to construct datastructures”.
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > unflatten :: [a] -> TreeF a [a]
unflatten ( []) = EmptyF
unflatten (x:[]) = LeafF x
unflatten ( xs) = NodeF l r where (l,r) = splitAt (length xs `div` 2) xs< / code > < / pre > < / div >
< p class = 'mb-3' >
From the type signature it’ s immediately obvious, that we take a list of ’ a’ s and use it to create a part of our tree.
< / p >
< p class = 'mb-3' >
The nice thing is that due to the fact that we haven’ t commited to a type in our tree nodes we can just put lists in there.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Aside: At this point we could use this Coalgebra to construct (unsorted) binary trees from lists:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > example1 = ana unflatten [1,3] == Fix (NodeF (Fix (LeafF 1)) (Fix (LeafF 3)))< / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
On to our sorting, tree-collapsing Algebra. Which again is just a creepy word for “function that is used to deconstruct datastructures”.
< / p >
< p class = 'mb-3' >
The function < code class = 'py-0.5 px-0.5 bg-gray-100' > mergeList< / code > is defined below and just merges two sorted lists into one sorted list in O(n), I would probably take this from the < code class = 'py-0.5 px-0.5 bg-gray-100' > ordlist< / code > package if I were to implement this < em > for real< / em > .
< / p >
< p class = 'mb-3' >
Again we see that we can just construct our sorted output list from a < code class = 'py-0.5 px-0.5 bg-gray-100' > TreeF< / code > that apparently contains just lists.
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > flatten :: Ord a => TreeF a [a] -> [a]
flatten EmptyF = []
flatten (LeafF c) = [c]
flatten (NodeF l r) = mergeLists l r < / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Aside: We could use a Coalgebra to deconstruct trees:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > example2 = cata flatten (Fix (NodeF (Fix (LeafF 3)) (Fix (LeafF 1)))) == [1,3]< / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Now we just combine the Coalgebra and the Algebra with one from the functions from Edwards < code class = 'py-0.5 px-0.5 bg-gray-100' > recursion-schemes< / code > library:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mergeSort :: Ord a => [a] -> [a]
mergeSort = hylo flatten unflatten
example3 = mergeSort [5,2,7,9,1,4] == [1,2,4,5,7,9] < / code > < / pre > < / div >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
What have we gained?
< / p >
< p class = 'mb-3' >
2022-08-25 04:18:18 +00:00
We have implemented a MergeSort variant in 9 lines of code, not counting the < code class = 'py-0.5 px-0.5 bg-gray-100' > mergeLists< / code > function below. Not bad, but < a href = 'http://en.literateprograms.org/Merge_sort_(Haskell)' class = 'text-purple-600 hover:underline' target = '_blank' rel = 'noopener' > this implementation< / a > is not much longer.
2022-08-24 14:52:32 +00:00
< / p >
< p class = 'mb-3' >
On the other hand the morphism based implementation cleanly describes what happens during construction and deconstruction of our intermediate structure.
< / p >
< p class = 'mb-3' >
My guess is that, as soon as the algortihms get more complex, this will really make a difference.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
At this point I wasn’ t sure if this was useful or remotely applicable. Telling someone “I spend a whole weekend learning about Hylomorphism” isn’ t something the cool developer kids do.
< / p >
< p class = 'mb-3' >
It appeared to me that maybe I should have a look at the Core to see what the compiler finally comes up with (edited for brevity):
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mergeSort :: [Integer] -> [Integer]
mergeSort =
\ (x :: [Integer]) ->
case x of wild {
[] -> [];
: x1 ds ->
case ds of _ {
[] -> : x1 ([]);
: ipv ipv1 ->
unfoldr
lvl9
(let {
p :: ([Integer], [Integer])
p =
case $wlenAcc wild 0 of ww { __DEFAULT ->
case divInt# ww 2 of ww4 { __DEFAULT ->
case tagToEnum# (< # ww4 0) of _ {
False ->
case $wsplitAt# ww4 wild of _ { (# ww2, ww3 #) -> (ww2, ww3) };
True -> ([], wild)
}
}
} } in
(case p of _ { (x2, ds1) -> mergeSort x2 },
case p of _ { (ds1, y) -> mergeSort y }))
}
}
end Rec }< / code > < / pre > < / div >
< p class = 'mb-3' >
While I am not really competent in reading Core and this is actually the first time I bothered to try, it is immediately obvious that there is no trace of any intermediate tree structure.
< / p >
< p class = 'mb-3' >
This is when it struck me. I was dazzled and amazed. And am still. Although we are writing our algorithm as if we are working on a real tree structure the library and the compiler are able to just remove the whole intermediate step.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Aftermath:
< / p >
< p class = 'mb-3' >
In the beginning I promised a way to work on non-functor data structures. Actually that was how I began to work with the < code class = 'py-0.5 px-0.5 bg-gray-100' > recursion-schemes< / code > library.
< / p >
< p class = 'mb-3' >
We are able to create a ‘ normal’ version of our tree from above:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > data Tree c = Empty | Leaf c | Node (Tree c) (Tree c)
deriving (Eq, Show)< / code > < / pre > < / div >
< p class = 'mb-3' >
But we can not use this directly with our (Co-)Algebras. Luckily Edward build a little bit of type magic into the library:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > type instance Base (Tree c) = (TreeF c)
instance Unfoldable (Tree c) where
embed EmptyF = Empty
embed (LeafF c) = Leaf c
embed (NodeF l r) = Node l r
instance Foldable (Tree c) where
project Empty = EmptyF
project (Leaf c) = LeafF c
project (Node l r) = NodeF l r< / code > < / pre > < / div >
< p class = 'mb-3' >
Without going into detail by doing this we establish a relationship between < code class = 'py-0.5 px-0.5 bg-gray-100' > Tree< / code > and < code class = 'py-0.5 px-0.5 bg-gray-100' > TreeF< / code > and teach the compiler how to translate between these types.
< / p >
< p class = 'mb-3' >
Now we can use our Alebra on our non functor type:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > example4 = cata flatten (Node (Leaf 'l') (Leaf 'r')) == "lr"< / code > < / pre > < / div >
< p class = 'mb-3' >
The great thing about this is that, looking at the Core output again, there is no traces of the < code class = 'py-0.5 px-0.5 bg-gray-100' > TreeF< / code > structure to be found. As far as I can tell, the algorithm is working directly on our < code class = 'py-0.5 px-0.5 bg-gray-100' > Tree< / code > type.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Literature:
< / p >
< ul class = 'my-3 ml-6 space-y-1 list-disc' >
< li >
2022-08-25 04:18:18 +00:00
< a href = 'https://www.fpcomplete.com/user/bartosz/understanding-algebras' class = 'text-purple-600 hover:underline' target = '_blank' rel = 'noopener' > Understanding F-Algebras< / a >
2022-08-24 14:52:32 +00:00
< / li >
< li >
2022-08-25 04:18:18 +00:00
< a href = 'http://www.timphilipwilliams.com/slides.html' class = 'text-purple-600 hover:underline' target = '_blank' rel = 'noopener' > Recursion Schemes by Example< / a >
2022-08-24 14:52:32 +00:00
< / li >
< li >
2022-08-25 04:18:18 +00:00
< a href = 'http://comonad.com/reader/2009/recursion-schemes/' class = 'text-purple-600 hover:underline' target = '_blank' rel = 'noopener' > Recursion Schemes: A Field Guide< / a >
2022-08-24 14:52:32 +00:00
< / li >
< li >
2022-08-25 04:18:18 +00:00
< a href = 'http://stackoverflow.com/questions/6941904/recursion-schemes-for-dummies' class = 'text-purple-600 hover:underline' target = '_blank' rel = 'noopener' > This StackOverflow question< / a >
2022-08-24 14:52:32 +00:00
< / li >
< / ul >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Appendix:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mergeLists :: Ord a => [a] -> [a] -> [a]
mergeLists = curry $ unfoldr c where
c ([], []) = Nothing
c ([], y:ys) = Just (y, ([], ys))
c (x:xs, []) = Just (x, (xs, []))
c (x:xs, y:ys) | x < = y = Just (x, (xs, y:ys))
| x > y = Just (y, (x:xs, ys))< / code > < / pre > < / div >
<!-- div class="flex items - center justify - center mt - 2">
< ema:metadata >
< with var = "template" >
< a class = "text-gray-300 hover:text-${theme}-600 text-sm" title = "Edit this page on GitHub"
href="${value:editBaseUrl}/${ema:note:source-path}">
< svg xmlns = "http://www.w3.org/2000/svg" class = "h-6 w-6" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" >
< path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
< / svg >
< / a >
< / with >
< / ema:metadata >
< /div -->
< / article >
< div class = 'flex flex-col lg:flex-row lg:space-x-2' >
< div class = 'flex-1 p-4 mt-8 bg-gray-100 rounded' >
< header class = 'mb-2 text-xl font-semibold text-gray-500' > Links to this page< / header >
< ul class = 'space-y-1' >
< li >
2022-08-25 04:18:18 +00:00
< a class = 'text-purple-600 mavenLinkBold hover:bg-purple-50' href = 'Haskell/Advantages' >
2022-08-24 14:52:32 +00:00
Talks und Posts zu Haskell
< / a >
< div class = 'mb-4 overflow-auto text-sm text-gray-500' >
2022-08-25 04:18:18 +00:00
< div class = 'pl-2 mt-2 border-l-2 border-purple-200 hover:border-purple-500' >
2022-08-24 14:52:32 +00:00
< div > < a href = 'https://www.youtube.com/watch?v=9EGYSb9vov8' class = 'text-gray-600 hover:underline' target = '_blank' rel = 'noopener' > Unifying Structured Recursion Schemes< / a > aka. < a href = 'Haskell/Code%20Snippets/Morphisms' class = 'text-gray-600 font-bold hover:bg-gray-50' data-wikilink-type = 'WikiLinkNormal' > The Morphism-Zoo< / a > < / div >
< / div >
2022-08-25 04:18:18 +00:00
< div class = 'pl-2 mt-2 border-l-2 border-purple-200 hover:border-purple-500' >
2022-08-24 14:52:32 +00:00
< div > < a href = 'https://www.fpcomplete.com/user/bartosz/understanding-algebras' class = 'text-gray-600 hover:underline' target = '_blank' rel = 'noopener' > Understanding F-Algebras< / a > schöne Erklärung. Man könnte danach anfangen den < a href = 'Haskell/Code%20Snippets/Morphisms' class = 'text-gray-600 font-bold hover:bg-gray-50' data-wikilink-type = 'WikiLinkBranch' > Morphismen-zoo< / a > zu verstehen…< / div >
< / div >
< / div >
< / li >
< / ul >
< / div >
< / div >
< section class = 'flex flex-wrap items-end justify-center my-4 space-x-2 space-y-2 font-mono text-sm' >
< / section >
<!-- What goes in this file will at the very end of the main div -->
< / main >
< / div >
< / div >
< footer class = 'flex items-center justify-center mt-2 mb-8 space-x-4 text-center text-gray-800' >
< div >
< a href = '' title = 'Go to Home page' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-6 h-6 hover:text-purple-700' fill = 'none' viewBox = '0 0 24 24' stroke = 'currentColor' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6' > < / path >
< / svg >
< / a >
< / div >
< div >
< a href = '-/all' title = 'View Index' >
2022-08-25 04:18:18 +00:00
< svg class = 'w-6 h-6 hover:text-purple-700' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4' >
< / path >
< / svg >
< / a >
< / div >
< div >
< a href = 'https://emanote.srid.ca' target = '_blank' title = 'Generated by Emanote 0.7.3.0' >
2022-08-25 04:18:18 +00:00
< img class = 'w-6 h-6 hover:text-purple-700' src = '_emanote-static/emanote-logo.svg' / >
2022-08-24 14:52:32 +00:00
< / a >
< / div >
< div >
< a href = '-/tags' title = 'View tags' >
2022-08-25 04:18:18 +00:00
< svg class = 'w-6 h-6 hover:text-purple-700' fill = 'none' stroke = 'currentColor' viewBox = '0 0 24 24' xmlns = 'http://www.w3.org/2000/svg' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z' >
< / path >
< / svg >
< / a >
< / div >
< div >
< a href = '-/tasks' title = 'View tasks' >
2022-08-25 04:18:18 +00:00
< svg xmlns = 'http://www.w3.org/2000/svg' class = 'w-6 h-6 hover:text-purple-700' fill = 'none' viewBox = '0 0 24 24' stroke = 'currentColor' >
2022-08-24 14:52:32 +00:00
< path stroke-linecap = 'round' stroke-linejoin = 'round' stroke-width = '2' d = 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z' > < / path >
< / svg >
< / a >
< / div >
< / footer >
< / div >
< div id = 'stork-search-container' class = 'hidden fixed w-screen h-screen inset-0 backdrop-filter backdrop-blur-sm' >
< div class = 'fixed w-screen h-screen inset-0' onclick = 'window.emanote.stork.toggleSearch()' > < / div >
< div class = 'container mx-auto p-10 mt-10' >
< div class = 'stork-wrapper-flat container mx-auto' >
< input id = 'stork-search-input' data-stork = 'emanote-search' class = 'stork-input' placeholder = 'Search (Ctrl+K) ...' / >
< div data-stork = 'emanote-search-output' class = 'stork-output' > < / div >
< / div >
< / div >
< / div >
< / body >
< / html >