1681 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1681 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						||
<html lang='en'>
 | 
						||
 | 
						||
<head>
 | 
						||
  <meta charset='UTF-8' />
 | 
						||
  <meta name='viewport' content='width=device-width, initial-scale=1' />
 | 
						||
  <title>
 | 
						||
    Lenses – Home
 | 
						||
  </title>
 | 
						||
  
 | 
						||
    
 | 
						||
      <meta property='og:description' content='Die Idee dahinter ist, dass man Zugriffsabstraktionen über Daten verknüpfen kann. Als einfachen Datenstruktur kann man einen Record mit der entsprechenden Syntax nehmen.' />
 | 
						||
      <meta property='og:site_name' content='Home' />
 | 
						||
      <meta property='og:image' content />
 | 
						||
      <meta property='og:type' content='website' />
 | 
						||
      <meta property='og:title' content='Lenses' />
 | 
						||
    
 | 
						||
    
 | 
						||
      <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=9a96156f-f633-42f8-838d-f30867d3069d' rel='stylesheet' type='text/css' />
 | 
						||
 | 
						||
  <style>
 | 
						||
    /* Heist error element */
 | 
						||
    strong.error {
 | 
						||
      color: lightcoral;
 | 
						||
      font-size: 90%;
 | 
						||
      font-family: monospace;
 | 
						||
    }
 | 
						||
 | 
						||
    /* External link icon */
 | 
						||
    a[data-linkicon]:not([data-linkicon=""]):not([data-linkicon="none"])::after {
 | 
						||
      /* filter converts black to rgb(156,163,175) */
 | 
						||
      filter: invert(71%) sepia(3%) saturate(904%) hue-rotate(179deg) brightness(92%) contrast(87%);
 | 
						||
      margin-left: 1px;
 | 
						||
    }
 | 
						||
 | 
						||
    a[data-linkicon]:not([data-linkicon=""]):not([data-linkicon="none"]):hover::after {
 | 
						||
      /* filter converts black to  rgb(175,85,99) */
 | 
						||
      filter: invert(32%) sepia(10%) saturate(834%) hue-rotate(176deg) brightness(92%) contrast(88%);
 | 
						||
    }
 | 
						||
 | 
						||
    a[data-linkicon=""]::after {
 | 
						||
      content: ""
 | 
						||
    }
 | 
						||
 | 
						||
    a[data-linkicon=none]::after {
 | 
						||
      content: ""
 | 
						||
    }
 | 
						||
 | 
						||
    a[data-linkicon="external"]::after {
 | 
						||
      content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='1em' fill='none' viewBox='0 0 24 24' stroke='black' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14' /%3E%3C/svg%3E");
 | 
						||
    }
 | 
						||
 | 
						||
    a[data-linkicon="external"][href^="mailto:"]::after {
 | 
						||
      content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='1em' fill='none' viewBox='0 0 24 24' stroke='black' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z' /%3E%3C/svg%3E");
 | 
						||
    }
 | 
						||
  </style>
 | 
						||
  <!-- What goes in this file will appear on near the end of <head>--><link rel='preload' href='_emanote-static/fonts/Work_Sans/WorkSans-VariableFont_wght.ttf' as='font' type='font/ttf' crossorigin />
 | 
						||
 | 
						||
<style>
 | 
						||
  @font-face {
 | 
						||
    font-family: 'WorkSans';
 | 
						||
    /* FIXME: This ought to be: ${ema:emanoteStaticLayerUrl}/fonts/Work_Sans/WorkSans-VariableFont_wght.ttf */
 | 
						||
    src: url(_emanote-static/fonts/Work_Sans/WorkSans-VariableFont_wght.ttf) format("truetype");
 | 
						||
    font-display: swap;
 | 
						||
  }
 | 
						||
 | 
						||
  body {
 | 
						||
    font-family: 'WorkSans', sans-serif;
 | 
						||
    font-variation-settings: 'wght' 350;
 | 
						||
  }
 | 
						||
 | 
						||
  a.mavenLinkBold {
 | 
						||
    font-variation-settings: 'wght' 400;
 | 
						||
  }
 | 
						||
 | 
						||
  strong {
 | 
						||
    font-variation-settings: 'wght' 500;
 | 
						||
  }
 | 
						||
 | 
						||
  h1,
 | 
						||
  h2,
 | 
						||
  h3,
 | 
						||
  h4,
 | 
						||
  h5,
 | 
						||
  h6,
 | 
						||
  header,
 | 
						||
  .header-font {
 | 
						||
    font-family: 'WorkSans', sans-serif;
 | 
						||
  }
 | 
						||
 | 
						||
  h1 {
 | 
						||
    font-variation-settings: 'wght' 500;
 | 
						||
  }
 | 
						||
 | 
						||
  h2 {
 | 
						||
    font-variation-settings: 'wght' 400;
 | 
						||
  }
 | 
						||
 | 
						||
  h3 {
 | 
						||
    font-variation-settings: 'wght' 300;
 | 
						||
  }
 | 
						||
</style>
 | 
						||
 | 
						||
 | 
						||
  
 | 
						||
    <link rel='stylesheet' href='_emanote-static/inverted-tree.css' />
 | 
						||
  
 | 
						||
  <link rel='stylesheet' href='_emanote-static/stork/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='_emanote-static/stork/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.initialize(baseUrl + '_emanote-static/stork/stork.wasm');
 | 
						||
              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='Coding'>
 | 
						||
                Coding
 | 
						||
              </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='Coding/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>
 | 
						||
          
 | 
						||
        
 | 
						||
      </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='Coding' href='Coding'>
 | 
						||
      Coding
 | 
						||
    </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='Haskell' href='Coding/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 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='Coding/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='Code-Snippets' href='Coding/Haskell/Code%20Snippets'>
 | 
						||
      Code-Snippets
 | 
						||
    </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 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='Coding/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='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='Lenses' href='Coding/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 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='Coding/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='Openapi-generator' href='Coding/OpenAPI'>
 | 
						||
      Openapi-generator
 | 
						||
    </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='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='Opinions' href='Opinions'>
 | 
						||
      Opinions
 | 
						||
    </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 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='Todo' href='TODO'>
 | 
						||
      Todo
 | 
						||
    </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='Coding/Haskell/Advantages'>
 | 
						||
      Talks und Posts zu Haskell
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='Coding/Haskell'>
 | 
						||
      Haskell
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='Coding'>
 | 
						||
      Coding
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href=''>
 | 
						||
      Home
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</li>
 | 
						||
          
 | 
						||
            <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='Coding/Haskell/FFPiH'>
 | 
						||
      Fortgeschrittene funktionale Programmierung in Haskell
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='About/CV'>
 | 
						||
      About me
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='About'>
 | 
						||
      About
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='Uni/Extracurricular'>
 | 
						||
      Studium generale / University-Life
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
    <ul>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
 | 
						||
  <div class='text-gray-900 forest-link'>
 | 
						||
    <a href='Uni'>
 | 
						||
      Uni
 | 
						||
    </a>
 | 
						||
  </div>
 | 
						||
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
</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 '>
 | 
						||
    Lenses
 | 
						||
  </a>
 | 
						||
</h1>
 | 
						||
            <article class='overflow-auto'>
 | 
						||
  <!-- What goes in this file will appear on top of note body-->
 | 
						||
  <h2 id='wofür-brauchen-wir-das-überhaupt' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Wofür brauchen wir das überhaupt?</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Die Idee dahinter ist, dass man Zugriffsabstraktionen über Daten verknüpfen kann. Als einfachen Datenstruktur kann man einen Record mit der entsprechenden Syntax nehmen.
 | 
						||
    </p>
 | 
						||
  <h3 id='beispiel' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Beispiel</h3><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Person = P { name :: String
 | 
						||
                , addr :: Address
 | 
						||
                , salary :: Int }
 | 
						||
data Address = A { road :: String
 | 
						||
                 , city :: String
 | 
						||
                 , postcode :: String }
 | 
						||
-- autogeneriert unten anderem: addr :: Person -> Address
 | 
						||
    
 | 
						||
    setName :: String -> Person -> Person
 | 
						||
    setName n p = p { name = n } --record update notation
 | 
						||
    
 | 
						||
    setPostcode :: String -> Person -> Person
 | 
						||
    setPostcode pc p
 | 
						||
        = p { addr = addr p { postcode = pc } }
 | 
						||
    -- update of a record inside a record</code></pre></div><h3 id='probleme' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Probleme</h3>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Probleme mit diesem Code:
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          für 1-Dimensionale Felder ist die record-syntax ok.
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          tiefere Ebenen nur umständlich zu erreichen
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          eigentlich wollen wir nur pe in p setzen, müssen aber über addr etc. gehen.
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          wir brauchen wissen über die “Zwischenstrukturen”, an denen wir nicht interessiert sind
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  <h3 id='was-wir-gern-hätten' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Was wir gern hätten</h3><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Person = P { name :: String
 | 
						||
                , addr :: Address
 | 
						||
                , salary :: Int }
 | 
						||
-- a lens for each field
 | 
						||
lname   :: Lens' Person String
 | 
						||
laddr   :: Lens' Person Adress
 | 
						||
lsalary :: Lens' Person Int
 | 
						||
-- getter/setter for them
 | 
						||
view    :: Lens' s a -> s -> a
 | 
						||
set     :: Lens' s a -> a -> s -> s
 | 
						||
-- lens-composition
 | 
						||
composeL :: Lens' s1 s2 -> Lens s2 a -> Lens' s1 a</code></pre></div><h3 id='wie-uns-das-hilft' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Wie uns das hilft</h3>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Mit diesen Dingen (wenn wir sie hätten) könnte man dann
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Person = P { name :: String
 | 
						||
                , addr :: Address
 | 
						||
                , salary :: Int }
 | 
						||
data Address = A { road :: String
 | 
						||
                 , city :: String
 | 
						||
                 , postcode :: String }
 | 
						||
setPostcode :: String -> Person -> Person
 | 
						||
setPostcode pc p
 | 
						||
    = set (laddr `composeL` lpostcode) pc p</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      machen und wäre fertig.
 | 
						||
    </p>
 | 
						||
  <h2 id='trivialer-ansatz' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Trivialer Ansatz</h2><h3 id='gettersetter-als-lens-methoden' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Getter/Setter als Lens-Methoden</h3><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data LensR s a = L { viewR :: s -> a
 | 
						||
                   , setR  :: a -> s -> s }
 | 
						||
 | 
						||
composeL (L v1 u1) (L v2 u2)
 | 
						||
  = L (\s -> v2 (v1 s))
 | 
						||
      (\a s -> u1 (u2 a (v1 s)) s)</code></pre></div><h3 id='wieso-ist-das-schlecht' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Wieso ist das schlecht?</h3>
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          extrem ineffizient
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Auslesen traversiert die Datenstruktur, dann wird die Funktion angewendet und zum setzen wird die Datenstruktur erneut traversiert:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>over :: LensR s a -> (a -> a) -> s -> s
 | 
						||
over ln f s = setR l (f (viewR l s)) s</code></pre></div>
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          Lösung: modify-funktion hinzufügen
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data LensR s a
 | 
						||
   = L { viewR :: s -> a
 | 
						||
       , setR  :: a -> s -> s
 | 
						||
       , mod   :: (a->a) -> s -> s
 | 
						||
       , modM  :: (a->Maybe a) -> s -> Maybe s
 | 
						||
       , modIO :: (a->IO a) -> s -> IO s }</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Neues Problem: Für jeden Spezialfall muss die Lens erweitert werden.
 | 
						||
    </p>
 | 
						||
  <h3 id='something-in-common' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Something in common</h3>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Man kann alle Monaden abstrahieren. Functor reicht schon:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data LensR s a
 | 
						||
   = L { viewR :: s -> a
 | 
						||
       , setR  :: a -> s -> s
 | 
						||
       , mod   :: (a->a) -> s -> s
 | 
						||
       , modF  :: Functor f => (a->f a) -> s -> f s }</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Idee: Die 3 darüberliegenden durch modF ausdrücken.
 | 
						||
    </p>
 | 
						||
  <h3 id='typ-einer-lens' class='mt-6 mb-2 text-3xl font-bold text-gray-700'>Typ einer Lens</h3>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wenn man das berücksichtigt, dann hat einen Lens folgenden Typ:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>type Lens' s a = forall f. Functor f
 | 
						||
                           => (a -> f a) -> s -> f s</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Allerdings haben wir dann noch unseren getter/setter:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data LensR s a = L { viewR :: s -> a
 | 
						||
                   , setR :: a -> s -> s }</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Stellt sich raus: Die sind isomorph! Auch wenn die von den Typen her komplett anders aussehen.
 | 
						||
    </p>
 | 
						||
  <h2 id='benutzen-einer-lens-als-setter' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Benutzen einer Lens als Setter</h2><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>set :: Lens' s a -> (a -> s -> s)
 | 
						||
set ln a s = --...umm...
 | 
						||
--:t ln => (a -> f a) -> s -> f s
 | 
						||
--            => get s out of f s to return it</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wir können für f einfach die “Identity”-Monade nehmen, die wir nachher wegcasten können.
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>newtype Identity a = Identity a
 | 
						||
-- Id :: a -> Identity a
 | 
						||
 | 
						||
runIdentity :: Identity s -> s
 | 
						||
runIdentity   (Identity x) = x
 | 
						||
 | 
						||
instance Functor Identity where
 | 
						||
    fmap f (Identity x) = Identity (f x)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      somit ist set einfach nur
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>set :: Lens' s a -> (a -> s -> s)
 | 
						||
set ln x s
 | 
						||
   = runIdentity (ls set_fld s)
 | 
						||
   where
 | 
						||
     set_fld :: a -> Identity a
 | 
						||
     set_fld _ = Identity x
 | 
						||
     -- a was the OLD value.
 | 
						||
     -- We throw that away and set the new value</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      oder kürzer (für nerds wie den Autor der Lens-Lib)
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>set :: Lens' s a -> (a -> s -> s)
 | 
						||
set ln x = runIdentity . ln (Identity . const x)</code></pre></div><h2 id='benutzen-einer-lens-als-modify' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Benutzen einer Lens als Modify</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Dasselbe wie Set, nur dass wir den Parameter nicht entsorgen, sondern in die mitgelieferte Funktion stopfen.
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>over :: Lens' s a -> (a -> a) -> s -> s
 | 
						||
over ln f = runIdentity . ln (Identity . f)</code></pre></div><h2 id='benutzen-einer-lens-als-getter' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Benutzen einer Lens als Getter</h2><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>view :: Lens' s a -> (s -> a)
 | 
						||
view ln s = --...umm...
 | 
						||
--:t ln => (a -> f a) -> s -> f s
 | 
						||
--            => get a out of the (f s) return-value
 | 
						||
--            Wait, WHAT?</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Auch hier gibt es einen netten Funktor. Wir packen das “a” einfach in das “f” und werfen das “s” am Ende weg.
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>newtype Const v a = Const v
 | 
						||
 | 
						||
getConst :: Const v a -> v
 | 
						||
getConst (Const x) = x
 | 
						||
 | 
						||
instance Functor (Const v) where
 | 
						||
    fmap f (Const x) = Const x
 | 
						||
    -- throw f away. Nothing changes our const!</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      somit ergibt sich
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>view :: Lens' s a -> (s -> a)
 | 
						||
view ln s 
 | 
						||
  = getConst (ln Const s)
 | 
						||
              -- Const :: s -> Const a s</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      oder nerdig
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>view :: Lens' s a -> (s -> a)
 | 
						||
view ln = getConst . ln Const</code></pre></div><h2 id='lenses-bauen' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Lenses bauen</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Nochmal kurz der Typ:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>type Lens' s a = forall f. Functor f
 | 
						||
                     => (a -> f a) -> s -> f s</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Für unser Personen-Beispiel vom Anfang:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Person = P { _name :: String, _salary :: Int }
 | 
						||
 | 
						||
name :: Lens' Person String
 | 
						||
-- name :: Functor f => (String -> f String)
 | 
						||
--                    -> Person -> f Person
 | 
						||
 | 
						||
name elt_fn (P n s)
 | 
						||
  = fmap (\n' -> P n' s) (elt_fn n)
 | 
						||
-- fmap :: Functor f => (a->b) -> f a -> f b - der Funktor, der alles verknüpft
 | 
						||
-- \n' -> .. :: String -> Person - Funktion um das Element zu lokalisieren (WO wird ersetzt/gelesen/...)
 | 
						||
-- elt_fn n  :: f String         - Funktion um das Element zu verändern (setzen, ändern, ...)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Die Lambda-Funktion ersetzt einfach den Namen. Häufig sieht man auch
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>name elt_fn (P n s)
 | 
						||
  = (\n' -> P n' s) <$> (elt_fn n)
 | 
						||
--  |    Focus    |     |Function|</code></pre></div><h2 id='wie-funktioniert-das-intern' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Wie funktioniert das intern?</h2><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>view name (P {_name="Fred", _salary=100})
 | 
						||
   -- inline view-function
 | 
						||
= getConst (name Const (P {_name="Fred", _salary=100})
 | 
						||
   -- inline name
 | 
						||
= getConst (fmap (\n' -> P n' 100) (Const "Fred"))
 | 
						||
   -- fmap f (Const x) = Const x - Definition von Const
 | 
						||
= getConst (Const "Fred")
 | 
						||
   -- getConst (Const x) = x
 | 
						||
= "Fred"</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Dieser Aufruf hat KEINE Runtime-Kosten, weil der Compiler direkt die Adresse des Feldes einsetzen kann. Der gesamte Boilerplate-Code wird vom Compiler wegoptimiert.
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Dies gilt für jeden Funktor mit newtype, da das nur ein Typalias ist.
 | 
						||
    </p>
 | 
						||
  <h2 id='composing-lenses-und-deren-benutzung' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Composing Lenses und deren Benutzung</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wie sehen denn die Typen aus?
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wir wollen ein
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <blockquote class='py-0.5 px-4 mb-3 italic border-l-4 bg-gray-50 text-gray-600 border-gray-400 quote'>
 | 
						||
      
 | 
						||
    <p class='mb-3'>
 | 
						||
      Lens’ s1 s2 -> Lens’ s2 a -> Lens’ s1 a
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    </blockquote>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wir haben 2 Lenses
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <blockquote class='py-0.5 px-4 mb-3 italic border-l-4 bg-gray-50 text-gray-600 border-gray-400 quote'>
 | 
						||
      
 | 
						||
    <p class='mb-3'>
 | 
						||
      ln1 :: (s2 -> f s2) -> (s1 -> f s1) ln2 :: (a -> f a) -> (s2 -> f s2)
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    </blockquote>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      wenn man scharf hinsieht, kann man die verbinden
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <blockquote class='py-0.5 px-4 mb-3 italic border-l-4 bg-gray-50 text-gray-600 border-gray-400 quote'>
 | 
						||
      
 | 
						||
    <p class='mb-3'>
 | 
						||
      ln1 . ln2 :: (a -> f s) -> (s1 -> f s1)
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    </blockquote>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      und erhält eine Lens. Sogar die Gewünschte!<br />Somit ist Lens-Composition einfach nur Function-Composition (.).
 | 
						||
    </p>
 | 
						||
  <h2 id='automatisieren-mit-template-haskell' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Automatisieren mit Template-Haskell</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Der Code um die Lenses zu bauen ist für records immer Identisch:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Person = P { _name :: String, _salary :: Int }
 | 
						||
 | 
						||
name :: Lens' Person String
 | 
						||
name elt_fn (P n s) = (\n' -> P n' s) <$> (elt_fn n)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Daher kann man einfach
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>import Control.Lens.TH
 | 
						||
data Person = P { _name :: String, _salary :: Int }
 | 
						||
 | 
						||
$(makeLenses ''Person)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      nehmen, was einem eine Lens für “name” und eine Lens für “salary” generiert.<br />Mit anderen Templates kann man auch weitere Dinge steuern (etwa wofür Lenses generiert werden, welches Prefix (statt _) man haben will etc. pp.).
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Will man das aber haben, muss man selbst in den Control.Lens.TH-Code schauen.
 | 
						||
    </p>
 | 
						||
  <h2 id='lenses-für-den-beispielcode' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Lenses für den Beispielcode</h2><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>import Control.Lens.TH
 | 
						||
 | 
						||
data Person = P { _name :: String
 | 
						||
                , _addr :: Address
 | 
						||
                , _salary :: Int }
 | 
						||
data Address = A { _road :: String
 | 
						||
                 , _city :: String
 | 
						||
                 , _postcode :: String }
 | 
						||
 | 
						||
$(makeLenses ''Person)
 | 
						||
$(makeLenses ''Address)
 | 
						||
 | 
						||
setPostcode :: String -> Person -> Person
 | 
						||
setPostcode pc p = set (addr . postcode) pc p</code></pre></div><h2 id='shortcuts-mit-line-noise' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Shortcuts mit “Line-Noise”</h2><div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>-- ...
 | 
						||
 | 
						||
setPostcode :: String -> Person -> Person
 | 
						||
setPostcode pc p = addr . postcode .~ pc     $ p
 | 
						||
--                 |   Focus     |set|to what|in where
 | 
						||
 | 
						||
getPostcode :: Person -> String
 | 
						||
getPostcode p = p   ^. $ addr . postcode
 | 
						||
--            |from|get|    Focus       |</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Es gibt drölf-zillionen weitere Infix-Operatoren (für Folds, Listenkonvertierungen, -traversierungen, …)
 | 
						||
    </p>
 | 
						||
  <h2 id='virtuelle-felder' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Virtuelle Felder</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Man kann mit Lenses sogar Felder emulieren, die gar nicht da sind. Angenommen folgender Code:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Temp = T { _fahrenheit :: Float }
 | 
						||
 | 
						||
$(makeLenses ''Temp)
 | 
						||
-- liefert Lens: fahrenheit :: Lens Temp Float
 | 
						||
 | 
						||
centigrade :: Lens Temp Float
 | 
						||
centigrade centi_fn (T faren)
 | 
						||
  = (\centi' -> T (cToF centi'))
 | 
						||
    <$> (centi_fn (fToC faren))
 | 
						||
-- cToF & fToC as Converter-Functions defined someplace else</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Hiermit kann man dann auch Funktionen, die auf Grad-Celsius rechnen auf Daten anwenden, die eigenlich nur Fahrenheit speichern, aber eine Umrechnung bereitstellen. Analog kann man auch einen Zeit-Datentypen definieren, der intern mit Sekunden rechnet (und somit garantiert frei von Fehlern wie -3 Minuten oder 37 Stunden ist)
 | 
						||
    </p>
 | 
						||
  <h2 id='non-record-strukturen' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Non-Record Strukturen</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Das ganze kann man auch parametrisieren und auf Non-Record-Strukturen anwenden. Beispielhaft an einer Map verdeutlicht:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>-- from Data.Lens.At
 | 
						||
at :: Ord k => k -> Lens' (Map k v) (Maybe v)
 | 
						||
 | 
						||
-- oder identisch, wenn man die Lens' auflöst:
 | 
						||
at :: Ord k, forall f. Functor f => k -> (Maybe v -> f Maybe v) -> Map k v -> f Map k v
 | 
						||
 | 
						||
at k mb_fn m
 | 
						||
  = wrap <$> (mb_fn mv)
 | 
						||
  where
 | 
						||
    mv = Map.lookup k m
 | 
						||
    
 | 
						||
    wrap :: Maybe v -> Map k v
 | 
						||
    wrap (Just v') = Map.insert k v' m
 | 
						||
    wrap Nothing   = case mv of
 | 
						||
                       Nothing -> m
 | 
						||
                       Just _  -> Map.delete k m
 | 
						||
 | 
						||
-- mb_fn :: Maybe v -> f Maybe v</code></pre></div><h2 id='weitere-beispiele' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Weitere Beispiele</h2>
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          
 | 
						||
    <p class='mb-3'>
 | 
						||
      Bitfields auf Strukturen die Bits haben (Ints, …) in Data.Bits.Lens
 | 
						||
    </p>
 | 
						||
  
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          
 | 
						||
    <p class='mb-3'>
 | 
						||
      Web-scraper in Package hexpat-lens
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>p ^.. _HTML' . to allNodes
 | 
						||
             . traverse . named "a"
 | 
						||
             . traverse . ix "href"
 | 
						||
             . filtered isLocal
 | 
						||
             . to trimSpaces</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Zieht alle externen Links aus dem gegebenen HTML-Code in p um weitere ziele fürs crawlen zu finden.
 | 
						||
    </p>
 | 
						||
  
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  <h2 id='erweiterungen' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Erweiterungen</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Bisher hatten wir Lenses nur auf Funktoren F. Die nächstmächtigere Klasse ist Applicative.
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>type Traversal' s a = forall f. Applicative f
 | 
						||
                             => (a -> f a) -> (s -> f s)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Da wir den Container identisch lassen (weder s noch a wurde angefasst) muss sich etwas anderes ändern. Statt eines einzelnen Focus erhalten wir viele Foci.
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Was ist ein Applicative überhaupt? Eine schwächere Monade (nur 1x Anwendung und kein Bind - dafür kann man die beliebig oft hintereinanderhängen).
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>class Functor f => Applicative f where
 | 
						||
  pure  :: a -> f a
 | 
						||
  (<*>) :: f (a -> b) -> f a -> f b
 | 
						||
 | 
						||
-- Monade als Applicative:
 | 
						||
pure = return
 | 
						||
mf <*> mx = do { f <- mf; x <- mx; return (f x) }</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Recap: Was macht eine Lens:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>data Adress = A { _road :: String
 | 
						||
                , _city :: String
 | 
						||
                , _postcode :: String }
 | 
						||
 | 
						||
road :: Lens' Adress String
 | 
						||
road elt_fn (A r c p) = (\r' -> A r' c p) <$> (elt_fn r)
 | 
						||
--                      |    "Hole"     |     | Thing to put in|</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wenn man nun road & city gleichzeitig bearbeiten will:
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>addr_strs :: Traversal' Address String
 | 
						||
addr_strs elt_fn (A r c p)
 | 
						||
  = ... (\r' c' -> A r' c' p)    .. (elt_fn r) .. (elt_fn c) ..
 | 
						||
--      | function with 2 "Holes"|  first Thing |  second Thing</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      fmap kann nur 1 Loch stopfen, aber nicht mit n Löchern umgehen. Applicative mit <*> kann das.<br />Somit gibt sich
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>addr_strs :: Traversal' Address String
 | 
						||
addr_strs elt_fn (A r c p)
 | 
						||
  = pure           (\r' c' -> A r' c' p)  <*> (elt_fn r) <*> (elt_fn c)
 | 
						||
--  lift in Appl. | function with 2 "Holes"|  first Thing |  second Thing
 | 
						||
-- oder kürzer
 | 
						||
addr_strs :: Traversal' Address String
 | 
						||
addr_strs elt_fn (A r c p)
 | 
						||
  = (\r' c' -> A r' c' p)  <$> (elt_fn r) <*> (elt_fn c)
 | 
						||
-- pure x <*> y == x <$> y</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Wie würd eine modify-funktion aussehen?
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>over :: Lens' s a -> (a -> a) -> s -> s
 | 
						||
over ln f = runIdentity . ln (Identity . f)
 | 
						||
 | 
						||
over :: Traversal' s a -> (a -> a) -> s -> s
 | 
						||
over ln f = runIdentity . ln (Identity . f)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Der Code ist derselbe - nur der Typ ist generischer. Auch die anderen Dinge funktioniert diese Erweiterung (für Identity und Const muss man noch ein paar dummy-Instanzen schreiben um sie von Functor auf Applicative oder Monad zu heben
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          konkret reicht hier die Instanzierung von Monoid). In der Lens-Library ist daher meist Monad m statt Functor f gefordert.
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  <h2 id='wozu-dienen-die-erweiterungen' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Wozu dienen die Erweiterungen?</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      Man kann mit Foci sehr selektiv vorgehen. Auch kann man diese durch Funktionen steuern. Beispisweise eine Funktion anwenden auf
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <ul class='my-3 ml-6 space-y-1 list-disc'>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          Jedes 2. Listenelement
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          Alle graden Elemente in einem Baum
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          Alle Namen in einer Tabelle, deren Gehalt > 10.000€ ist
 | 
						||
        </li>
 | 
						||
      
 | 
						||
    </ul>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Traversals und Lenses kann man trivial kombinieren (<code class='py-0.5 px-0.5 bg-gray-100'>lens . lens</code> => <code class='py-0.5 px-0.5 bg-gray-100'>lens</code>, <code class='py-0.5 px-0.5 bg-gray-100'>lens . traversal</code> => <code class='py-0.5 px-0.5 bg-gray-100'>traversal</code> etc.)
 | 
						||
    </p>
 | 
						||
  <h2 id='wie-es-in-lens-wirklich-aussieht' class='inline-block mt-6 mb-4 text-4xl font-bold text-gray-700 border-b-2'>Wie es in Lens wirklich aussieht</h2>
 | 
						||
    <p class='mb-3'>
 | 
						||
      In diesem Artikel wurde nur auf Monomorphic Lenses eingegangen. In der richtigen Library ist eine Lens
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>type Lens' s a = Lens s s a a
 | 
						||
type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t)</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      sodass sich auch die Typen ändern können um z.B. automatisch einen Konvertierten (sicheren) Typen aus einer unsicheren Datenstruktur zu geben.
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Die modify-Funktion over ist auch
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>> over :: Profunctor p => Setting p s t a b -> p a b -> s -> t</code></pre></div>
 | 
						||
    <blockquote class='py-0.5 px-4 mb-3 italic border-l-4 bg-gray-50 text-gray-600 border-gray-400 quote'>
 | 
						||
      
 | 
						||
    <p class='mb-3'>
 | 
						||
      <em>Edward is deeply in thrall to abstractionitis</em> - Simon Peyton Jones
 | 
						||
    </p>
 | 
						||
  
 | 
						||
    </blockquote>
 | 
						||
  
 | 
						||
    <p class='mb-3'>
 | 
						||
      Lens alleine definiert 39 newtypes, 34 data-types und 194 Typsynonyme…<br />Ausschnitt
 | 
						||
    </p>
 | 
						||
  <div class='py-0.5 mb-3 text-sm'><pre><code class='haskell language-haskell'>-- traverseOf :: Functor f => Iso s t a b           -> (a -> f b) -> s -> f t
 | 
						||
-- traverseOf :: Functor f => Lens s t a b          -> (a -> f b) -> s -> f t
 | 
						||
-- traverseOf :: Applicative f => Traversal s t a b -> (a -> f b) -> s -> f t
 | 
						||
 | 
						||
traverseOf :: Over p f s t a b -> p a (f b) -> s -> f t</code></pre></div>
 | 
						||
    <p class='mb-3'>
 | 
						||
      dafuq?
 | 
						||
    </p>
 | 
						||
  
 | 
						||
 | 
						||
  <!-- 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='Coding/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://skillsmatter.com/skillscasts/4251-lenses-compositional-data-access-and-manipulation' class='text-gray-600 hover:underline' data-linkicon='external' target='_blank' rel='noopener'>Lenses</a> (Registrierung nötig - kostenfrei), siehe auch: <a href='Coding/Haskell/Lenses' class='text-gray-600 font-bold hover:bg-gray-50' data-wikilink-type='WikiLinkBranch'>Lenses</a></div>
 | 
						||
    </div>
 | 
						||
  
 | 
						||
</div>
 | 
						||
          
 | 
						||
        </li>
 | 
						||
      
 | 
						||
        <li>
 | 
						||
          <a class='text-purple-600 mavenLinkBold hover:bg-purple-50' href='Coding/Haskell/FFPiH'>
 | 
						||
            Fortgeschrittene funktionale Programmierung in 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>Umschreiben von explizitem Argument-Passing hin zu Monad-Transformers mit stateful <a href='Coding/Haskell/Lenses' class='text-gray-600 font-bold hover:bg-gray-50' data-wikilink-type='WikiLinkBranch'>lenses</a></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.8.1.10'>
 | 
						||
      <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>
 |