emanote/static_gen/Haskell/Code Snippets/Morphisms.html
2022-08-25 06:18:18 +02:00

1198 lines
39 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>
<link href='tailwind.css?instanceId=ecadcd50-ecaf-4d6e-98ea-7932c3b3d351' rel='stylesheet' type='text/css' />
<!-- 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()'>
<svg xmlns='http://www.w3.org/2000/svg' style='width: 1rem;' class='hover:text-purple-700' f
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>
<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')">
<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'>
<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'>
<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'>
<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'>
<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()'>
<svg xmlns='http://www.w3.org/2000/svg' style='width: 1rem;' class='hover:text-purple-700' f
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'>
<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>
</svg>
<a class='hover:underline truncate' title='About' href='About'>
About
</a>
<span class='text-gray-300' title='3 children inside'>
3
</span>
</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-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>
</svg>
<a class='hover:underline truncate' title='Android' href='Android'>
Android
</a>
<span class='text-gray-300' title='1 children inside'>
1
</span>
</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>
<a class='font-bold text-purple-600 hover:underline truncate' title='*-Morpisms' href='Haskell/Code%20Snippets/Morphisms'>
*-Morpisms
</a>
</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 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>
</div>
<!-- Node's children forest, displayed only on active trees
TODO: Use <details> to toggle visibility?
-->
</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'>
<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>
</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 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>
</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 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>
</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-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>
</svg>
<a class='hover:underline truncate' title='Webapp-Development in Haskell' href='Haskell/Webapp-Example'>
Webapp-Development in Haskell
</a>
<span class='text-gray-300' title='2 children inside'>
2
</span>
</div>
<!-- Node's children forest, displayed only on active trees
TODO: Use <details> to toggle visibility?
-->
</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'>
<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>
</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-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>
</svg>
<a class='hover:underline truncate' title='Uni' href='Uni'>
Uni
</a>
<span class='text-gray-300' title='2 children inside'>
2
</span>
</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-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>
</svg>
<a class='hover:underline truncate' title='Unix' href='Unix'>
Unix
</a>
<span class='text-gray-300' title='1 children inside'>
1
</span>
</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>
<h1 class='flex items-end justify-center mb-4 p-3 bg-purple-100 text-5xl font-extrabold text-black rounded'>
<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] -&gt; 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 its immediately obvious, that we take a list of as 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 havent 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 =&gt; TreeF a [a] -&gt; [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 =&gt; [a] -&gt; [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'>
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.
</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 wasnt sure if this was useful or remotely applicable. Telling someone “I spend a whole weekend learning about Hylomorphism” isnt 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] -&gt; [Integer]
mergeSort =
\ (x :: [Integer]) -&gt;
case x of wild {
[] -&gt; [];
: x1 ds -&gt;
case ds of _ {
[] -&gt; : x1 ([]);
: ipv ipv1 -&gt;
unfoldr
lvl9
(let {
p :: ([Integer], [Integer])
p =
case $wlenAcc wild 0 of ww { __DEFAULT -&gt;
case divInt# ww 2 of ww4 { __DEFAULT -&gt;
case tagToEnum# (&lt;# ww4 0) of _ {
False -&gt;
case $wsplitAt# ww4 wild of _ { (# ww2, ww3 #) -&gt; (ww2, ww3) };
True -&gt; ([], wild)
}
}
} } in
(case p of _ { (x2, ds1) -&gt; mergeSort x2 },
case p of _ { (ds1, y) -&gt; 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>
<a href='https://www.fpcomplete.com/user/bartosz/understanding-algebras' class='text-purple-600 hover:underline' target='_blank' rel='noopener'>Understanding F-Algebras</a>
</li>
<li>
<a href='http://www.timphilipwilliams.com/slides.html' class='text-purple-600 hover:underline' target='_blank' rel='noopener'>Recursion Schemes by Example</a>
</li>
<li>
<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>
</li>
<li>
<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>
</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 =&gt; [a] -&gt; [a] -&gt; [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 &lt;= y = Just (x, (xs, y:ys))
| x &gt; 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>
<a class='text-purple-600 mavenLinkBold hover:bg-purple-50' href='Haskell/Advantages'>
Talks und Posts zu Haskell
</a>
<div class='mb-4 overflow-auto text-sm text-gray-500'>
<div class='pl-2 mt-2 border-l-2 border-purple-200 hover:border-purple-500'>
<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>
<div class='pl-2 mt-2 border-l-2 border-purple-200 hover:border-purple-500'>
<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'>
<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'>
<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'>
<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'>
<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'>
<img class='w-6 h-6 hover:text-purple-700' src='_emanote-static/emanote-logo.svg' />
</a>
</div>
<div>
<a href='-/tags' title='View tags'>
<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'>
<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'>
<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'>
<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>