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 >
Monoid? Da war doch was… – Home
< / title >
< meta property = 'og:description' content = 'Stellen wir uns vor, dass wir eine Funktion schreiben, die einen String bekommt (mehrere Lines mit ACSII-Text) und dieses Wort-für-Wort rückwärts ausgeben soll. Das ist ein einfacher Einzeiler:' / >
< meta property = 'og:site_name' content = 'Home' / >
< meta property = 'og:image' content / >
< meta property = 'og:type' content = 'website' / >
< meta property = 'og:title' content = 'Monoid? Da war doch was…' / >
< 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 -->
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 = '*-Morpisms' href = 'Haskell/Code%20Snippets/Morphisms' >
*-Morpisms
< / 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 -->
<!-- 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 = 'Monoid? Da war doch was…' href = 'Haskell/Code%20Snippets/Monoid' >
2022-08-24 14:52:32 +00:00
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 -->
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/Code%20Snippets' >
Code-Snippets
< / 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 >
< / 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 ' >
Monoid? Da war doch was…
< / a >
< / h1 >
< article class = 'overflow-auto' >
<!-- What goes in this file will appear on top of note body -->
< p class = 'mb-3' >
Stellen wir uns vor, dass wir eine Funktion schreiben, die einen String bekommt (mehrere Lines mit ACSII-Text) und dieses Wort-für-Wort rückwärts ausgeben soll. Das ist ein einfacher Einzeiler:
< / p >
2022-08-25 03:26:25 +00:00
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > module Main where
2022-08-24 14:52:32 +00:00
import System.Environment (getArgs)
import Data.Monoid (mconcat)
import Data.Functor ((< $> ))
main = do
ls < - readFile =< < head < $> getArgs
mconcat < $> mapM (putStrLn . unwords . reverse . words) (lines ls) --die eigentliche Funktion, ls ist das argument.< / code > < / pre > < / div >
< p class = 'mb-3' >
Was passiert hier an Vodoo? Und was machen die ganzen wilden Zeichen da?
< / p >
< p class = 'mb-3' >
Gehen wir die Main zeilenweise durch: Wir lesen die Datei, die im ersten Kommandozeilen-Argument gegeben wird. getArgs hat folgende Signatur:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > getArgs :: IO [String]< / code > < / pre > < / div >
< p class = 'mb-3' >
Wir bekommen als eine Liste der Argumente. Wir wollen nur das erste. Also machen wir head getArgs. Allerdings fliegt uns dann ein Fehler. head sieht nämlich so aus:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > head :: [a] -> a< / code > < / pre > < / div >
< p class = 'mb-3' >
Irgendwie müssen wird as < strong > in< / strong > das IO bekommen. Hierzu gibt es fmap. Somit ist
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > fmap head :: IO [a] -> IO a< / code > < / pre > < / div >
< p class = 'mb-3' >
Ein inline-Alias (um die Funktion links und das Argument rechts zu schreiben und sich ne Menge Klammern zu sparen) ist < $> . Somit ist schlussendlich der Inhalt der Datei aus dem ersten Argument (lazy) in ls.
< / p >
< p class = 'mb-3' >
Eine andere Möglichkeit sich das (in diesem Fall) zu merken, bzw. drauf zu kommen ist, dass [] AUCH ein Funktor (sogar eine Monade) ist. Man könnte das also auch so schreiben:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > head :: [] a -> a
head :: Functor f => [] (f a) -> f a -- das "a" geschickt ersetzt zur Verdeutlichung
getArgs :: IO [] String
fmap head :: Functor f => f [] a -> f a< / code > < / pre > < / div >
< p class = 'mb-3' >
fmap “packt” die Funktion quasi 1 Umgebung (Funktor, Monade, ..) weiter rein - Sei es nun in Maybe, Either oder irgendwas anderes.
< / p >
< p class = 'mb-3' >
Alternatives (ausführliches) Beispiel am Ende.
< / p >
< p class = 'mb-3' >
Wenn wir uns die Signatur ansehen, dann haben wir nun
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > head < $> getArgs :: IO String< / code > < / pre > < / div >
< p class = 'mb-3' >
readFile will aber nun ein String haben. Man kann nun
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f < - head < $> getArgs
ls < - readFile f< / code > < / pre > < / div >
< p class = 'mb-3' >
kann man auch “inline” mit =< < die Sachen “auspacken”.
< / p >
< p class = 'mb-3' >
Die 2. Zeile lesen wir nun einfach “von hinten”, wie man das meistens tun sollte. Hier ist ein
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > lines ls :: [String]< / code > < / pre > < / div >
< p class = 'mb-3' >
was uns den Inhalt der Datei zeilenweise gibt. Mit jeder Zeile möchten wir nun folgendes machen:
< / p >
< ul class = 'my-3 ml-6 space-y-1 list-decimal list-inside' >
< li >
nach Wörtern trennen (words)
< / li >
< li >
Wörter in der reihenfolge umkehren (reverse)
< / li >
< li >
Wörter wider zu einer Zeile zusammensetzen (unwords)
< / li >
< li >
diese Zeile ausgeben (putStrLn)
< / li >
< / ul >
< p class = 'mb-3' >
Wenn wir uns die Signatur ansehen:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > (putStrLn . unwords . reverse . words) :: String -> IO ()< / code > < / pre > < / div >
< p class = 'mb-3' >
Das mag im ersten Moment verwirren, daher noch die Signaturen der Einzelfunktionen:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > words :: String -> [String]
reverse :: [a] -> [a]
unwords :: [String] -> String
putStrLn :: String -> IO ()< / code > < / pre > < / div >
< p class = 'mb-3' >
Da wir am Ende in der IO-Monade landen müssen wir das auf unsere Zeilen mit mapM statt map anwenden. Dies sorgt auch dafür, dass die Liste der reihe nach durchgegangen wird. mapM mit unserer Funktion schaut dann so aus:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mapM (putStrLn . unwords . reverse . words) :: [String] -> [IO ()]< / code > < / pre > < / div >
< p class = 'mb-3' >
eek! Das [IO ()] sieht ekelig aus. Wir haben eine Liste von IO-gar nichts. Das können wir eigentlich entsorgen. Da wir innerhalb der main-Funktion in einer IO-Monade sind, wollen wir IO () anstatt [IO ()] zurück haben.
< / p >
< p class = 'mb-3' >
Wenn wir uns jetzt erinnern, dass [] auch nur eine Monade ist und dass jede Monade ein Monoid ist, dann ist die Lösung einfach. Monoide haben eine “append”-funktion (mappend oder (< > ) genannt). Wenn wir “nichts” an “nichts” anhängen, dann erhalten wir …. < em > Trommelwirbel< / em > “nichts”! Wir müssen die [IO ()]-Liste also “nur noch” mit mappend falten. Hierzu gibt es schon eine vorgefertigte Funktion:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mconcat :: [a] -> a
mconcat = foldr mappend mempty< / code > < / pre > < / div >
< p class = 'mb-3' >
Was genau die gewünschte Faltung macht. Wir müssen nun wieder fmap nehmen, da wir die Liste selbst falten wollen - und nicht map, welches auf den IO () innerhalb der Liste arbeiten würde. Durch die Faltung fällt die Liste nun auf IO () zusammen.
< / p >
< p class = 'mb-3' >
Viel Voodoo in wenig Code, aber wenn man sich dran gewöhnt hat, sind Monaden in Monaden auch nicht schlimm. Man muss sich immer nur richtig “rein” fmap’ en.
< / p >
< hr class = 'mb-3' / >
< p class = 'mb-3' >
Kleinen Tipp gab es noch: mapM_ macht genau das, was oben mit mconcat erreicht werden sollte. Somit kann man auch
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > mapM_ (putStrLn . unwords . reverse . words) (lines ls)< / code > < / pre > < / div >
< p class = 'mb-3' >
schreiben. Ich hab es aber mal wegen der klarheit oben so gelassen.
< / p >
< h2 id = 'alternatives-fmap-beispiel' class = 'inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2' > Alternatives fmap-Beispiel< / h2 >
< p class = 'mb-3' >
Nehmen wir als alternatives Beispiel mal an:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > a :: IO Maybe State t< / code > < / pre > < / div >
< p class = 'mb-3' >
Um Funktionen vom Typ
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f :: IO a -> IO a
f a -- valide< / code > < / pre > < / div >
< p class = 'mb-3' >
zu nehmen, brauchen wir nichts machen. Bei
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f' :: Maybe a -> Maybe a< / code > < / pre > < / div >
< p class = 'mb-3' >
brauchen wir 1 fmap, also ein
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f' a -- error
f' < $> a< / code > < / pre > < / div >
< p class = 'mb-3' >
um eine Funktion
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f'' :: State t -> State t< / code > < / pre > < / div >
< p class = 'mb-3' >
zu benutzen folglich:
< / p >
< div class = 'py-0.5 mb-3 text-sm' > < pre > < code class = 'haskell language-haskell' > f'' a -- error
f'' < $> a -- error
fmap f'' < $> a< / 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 >
< 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 >