sc-lectures/4.html
2020-05-24 00:51:09 +03:00

679 lines
74 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="author" content="Ilya Kostyuchenko">
<title>4</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="reveal.js/css/reset.css">
<link rel="stylesheet" href="reveal.js/css/reveal.css">
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #ffffff; background-color: #000000; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span. { color: #ffffff; } /* Normal */
code span.al { color: #95da4c; background-color: #4d1f24; font-weight: bold; } /* Alert */
code span.an { color: #86d5a4; } /* Annotation */
code span.at { color: #94cbf0; } /* Attribute */
code span.bn { color: #ffb06a; } /* BaseN */
code span.bu { color: #bdd1d3; } /* BuiltIn */
code span.cf { color: #ffd998; font-weight: bold; } /* ControlFlow */
code span.ch { color: #a4e0ff; } /* Char */
code span.cn { color: #73d9d9; font-weight: bold; } /* Constant */
code span.co { color: #a1a6a8; } /* Comment */
code span.cv { color: #b6c8c9; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #7cc0ec; } /* DataType */
code span.dv { color: #f6b77f; } /* DecVal */
code span.er { color: #e9848e; text-decoration: underline; } /* Error */
code span.ex { color: #96d5ff; font-weight: bold; } /* Extension */
code span.fl { color: #fdae67; } /* Float */
code span.fu { color: #d487f4; } /* Function */
code span.im { color: #76e8a6; } /* Import */
code span.in { color: #f6b176; } /* Information */
code span.kw { color: #ebebc9; font-weight: bold; } /* Keyword */
code span.op { color: #ececde; } /* Operator */
code span.ot { color: #86e9b0; } /* Other */
code span.pp { color: #62e298; } /* Preprocessor */
code span.re { color: #83c7f4; background-color: #153042; } /* RegionMarker */
code span.sc { color: #80ccf4; } /* SpecialChar */
code span.ss { color: #ff909b; } /* SpecialString */
code span.st { color: #ff9f9f; } /* String */
code span.va { color: #56d4d4; } /* Variable */
code span.vs { color: #eca2a9; } /* VerbatimString */
code span.wa { color: #eca2a9; } /* Warning */
</style>
<link rel="stylesheet" href="reveal.js/css/theme/superblack.css" id="theme">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'reveal.js/css/print/pdf.css' : 'reveal.js/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="reveal.js/lib/js/html5shiv.js"></script>
<![endif]-->
<style>
div.sourceCode {
background-color: transparent;
overflow: auto;
margin: 0em;
}
pre.sourceCode {
margin: 8px auto;
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section id="функциональное-программирование" class="slide level1">
<h1>Функциональное программирование</h1>
</section>
<section class="slide level1">
<h2 id="напоминалочка">Напоминалочка</h2>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="ot"> fmap ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span></code></pre></div>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="ot"> (&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="ot"> pure ::</span> a <span class="ot">-&gt;</span> f a</span></code></pre></div>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Monad</span> f <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="ot"> (&gt;&gt;=) ::</span> f a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> f b</span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="ot"> return ::</span> a <span class="ot">-&gt;</span> f a</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="either">Either</h2>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">data</span> <span class="dt">Either</span> a b <span class="ot">=</span> <span class="dt">Left</span> a <span class="op">|</span> <span class="dt">Right</span> b</span></code></pre></div>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1"></a><span class="ot">throwError ::</span> e <span class="ot">-&gt;</span> <span class="dt">Either</span> e a</span>
<span id="cb5-2"><a href="#cb5-2"></a>throwError <span class="ot">=</span> <span class="dt">Left</span></span></code></pre></div>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">data</span> <span class="dt">PaymentError</span> <span class="ot">=</span> <span class="dt">InsufficientBalance</span></span>
<span id="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="ot">pay ::</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> <span class="dt">Balance</span></span>
<span id="cb6-4"><a href="#cb6-4"></a>pay balance price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> <span class="kw">let</span> newBalance <span class="ot">=</span> balance <span class="op">-</span> price</span>
<span id="cb6-6"><a href="#cb6-6"></a> when (newBalance <span class="op">&lt;</span> <span class="dv">0</span>) (throwError <span class="dt">InsufficientBalance</span>)</span>
<span id="cb6-7"><a href="#cb6-7"></a> <span class="fu">return</span> newBalance</span></code></pre></div>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1"></a><span class="ot">when ::</span> (<span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> f () <span class="ot">-&gt;</span> f ()</span>
<span id="cb7-2"><a href="#cb7-2"></a>when p s <span class="ot">=</span> <span class="kw">if</span> p <span class="kw">then</span> s <span class="kw">else</span> <span class="fu">pure</span> ()</span></code></pre></div>
</section>
<section id="state" class="slide level1">
<h1>State</h1>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1"></a><span class="ot">get ::</span> <span class="dt">State</span> s s</span>
<span id="cb9-2"><a href="#cb9-2"></a>get <span class="ot">=</span> <span class="dt">State</span> (\s <span class="ot">-&gt;</span> (s, s))</span>
<span id="cb9-3"><a href="#cb9-3"></a></span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="ot">put ::</span> s <span class="ot">-&gt;</span> <span class="dt">State</span> s ()</span>
<span id="cb9-5"><a href="#cb9-5"></a>put s <span class="ot">=</span> <span class="dt">State</span> (\_ <span class="ot">-&gt;</span> (_, s))</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1"></a><span class="ot">getNewId ::</span> <span class="dt">State</span> <span class="dt">TransactionId</span> <span class="dt">TransactionId</span></span>
<span id="cb10-2"><a href="#cb10-2"></a>getNewId <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-3"><a href="#cb10-3"></a> newId <span class="ot">&lt;-</span> get</span>
<span id="cb10-4"><a href="#cb10-4"></a> put (<span class="fu">succ</span> newId)</span>
<span id="cb10-5"><a href="#cb10-5"></a> <span class="fu">return</span> newId</span>
<span id="cb10-6"><a href="#cb10-6"></a></span>
<span id="cb10-7"><a href="#cb10-7"></a><span class="kw">data</span> <span class="dt">Transaction</span> <span class="ot">=</span> <span class="dt">Transaction</span></span>
<span id="cb10-8"><a href="#cb10-8"></a> {<span class="ot"> transactionId ::</span> <span class="dt">TransactionId</span>,</span>
<span id="cb10-9"><a href="#cb10-9"></a><span class="ot"> transactionAmount ::</span> <span class="dt">Price</span></span>
<span id="cb10-10"><a href="#cb10-10"></a> }</span></code></pre></div>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1"></a><span class="ot">registerPayment ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">TransactionId</span> <span class="dt">Transaction</span></span>
<span id="cb11-2"><a href="#cb11-2"></a>registerPayment price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3"></a> newId <span class="ot">&lt;-</span> getNewId</span>
<span id="cb11-4"><a href="#cb11-4"></a> <span class="fu">return</span> <span class="dt">Transaction</span></span>
<span id="cb11-5"><a href="#cb11-5"></a> { transactionId <span class="ot">=</span> newId</span>
<span id="cb11-6"><a href="#cb11-6"></a> transactionAmount <span class="ot">=</span> price</span>
<span id="cb11-7"><a href="#cb11-7"></a> }</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1"></a><span class="ot">registerPayment ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">TransactionId</span> <span class="dt">Transaction</span></span>
<span id="cb12-2"><a href="#cb12-2"></a><span class="ot">pay ::</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> <span class="dt">Balance</span></span></code></pre></div>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1"></a>payAndRegister balance price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-2"><a href="#cb13-2"></a> newBalance <span class="ot">&lt;-</span> pay balance price</span>
<span id="cb13-3"><a href="#cb13-3"></a> transacation <span class="ot">&lt;-</span> registerPayment price</span>
<span id="cb13-4"><a href="#cb13-4"></a> <span class="fu">return</span> (newBalance, transaction)</span></code></pre></div>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1"></a><span class="ot">(&gt;=&gt;) ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> (b <span class="ot">-&gt;</span> m c) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m c)</span></code></pre></div>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1"></a><span class="co">-- Такого нет</span></span>
<span id="cb15-2"><a href="#cb15-2"></a>(<span class="op">&gt;=&gt;</span>)</span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="ot"> ::</span> (<span class="dt">Monad</span> m, <span class="dt">Monad</span> n)</span>
<span id="cb15-4"><a href="#cb15-4"></a> <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> (b <span class="ot">-&gt;</span> n c) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="op">?</span> c)</span></code></pre></div>
<p><span class="fragment">На каждый чих нужно создавать новый тип?</span></p>
</section>
<section class="slide level1">
<p>Мы хотим:</p>
<ol type="1">
<li class="fragment">Отделить эффекты от конкретной монады</li>
<li class="fragment">Получить возможность комбинировать разные эффекты</li>
</ol>
<p><span class="fragment">(И чтобы не надо было на каждый случай новый тип создавать)</span></p>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1"></a><span class="ot">registerPayment ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">TransactionId</span> <span class="dt">Transaction</span></span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="ot">pay ::</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> <span class="dt">Balance</span></span></code></pre></div>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1"></a>registerPayment</span>
<span id="cb17-2"><a href="#cb17-2"></a><span class="ot"> ::</span> <span class="dt">MonadState</span> <span class="dt">TransactionId</span> m</span>
<span id="cb17-3"><a href="#cb17-3"></a> <span class="ot">=&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m <span class="dt">Transaction</span></span>
<span id="cb17-4"><a href="#cb17-4"></a>pay</span>
<span id="cb17-5"><a href="#cb17-5"></a><span class="ot"> ::</span> <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m</span>
<span id="cb17-6"><a href="#cb17-6"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m <span class="dt">Balance</span></span></code></pre></div>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1"></a>payAndRegister</span>
<span id="cb18-2"><a href="#cb18-2"></a><span class="ot"> ::</span> (<span class="dt">MonadState</span> <span class="dt">TransactionId</span> m, <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m)</span>
<span id="cb18-3"><a href="#cb18-3"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span></code></pre></div>
</section>
<section class="slide level1">
<p>На самом деле мы хотим чтобы понятие “state” не было привязано к конкретной монаде.</p>
<p><span class="fragment">Мы хотим чтобы “базовые операции” не были привязаны к конкретной монаде.</span></p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1"></a><span class="co">-- Было</span></span>
<span id="cb19-2"><a href="#cb19-2"></a><span class="ot">get ::</span> <span class="dt">State</span> s s</span>
<span id="cb19-3"><a href="#cb19-3"></a><span class="ot">put ::</span> s <span class="ot">-&gt;</span> <span class="dt">State</span> s ()</span></code></pre></div>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1"></a><span class="co">-- Стало</span></span>
<span id="cb20-2"><a href="#cb20-2"></a><span class="ot">get ::</span> <span class="dt">MonadState</span> s m <span class="ot">=&gt;</span> m s</span>
<span id="cb20-3"><a href="#cb20-3"></a><span class="ot">put ::</span> <span class="dt">MonadState</span> s m <span class="ot">=&gt;</span> s <span class="ot">-&gt;</span> m ()</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="monadstate">MonadState</h2>
</section>
<section class="slide level1">
<!--
```{ .haskell .fragment }
class MonadState s m | m -> s where
get :: m s
put :: s -> m ()
```
[`m -> s` означает что для каждого `m` может быть строго один `s`.]{ .fragment }
[(Это нужно чтобы когда вы делаете `get` было понятно что вам возвращать.)]{ .fragment } -->
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadState</span> s m <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2"></a><span class="ot"> get ::</span> m s</span>
<span id="cb21-3"><a href="#cb21-3"></a><span class="ot"> put ::</span> s <span class="ot">-&gt;</span> m ()</span></code></pre></div>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span>
<span id="cb22-2"><a href="#cb22-2"></a></span>
<span id="cb22-3"><a href="#cb22-3"></a><span class="kw">instance</span> <span class="dt">MonadState</span> s (<span class="dt">State</span> s) <span class="kw">where</span></span>
<span id="cb22-4"><a href="#cb22-4"></a> get <span class="ot">=</span> <span class="dt">State</span> (\s <span class="ot">-&gt;</span> (s, s))</span>
<span id="cb22-5"><a href="#cb22-5"></a> put s <span class="ot">=</span> <span class="dt">State</span> (\_ <span class="ot">-&gt;</span> ((), s))</span></code></pre></div>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1"></a><span class="ot">getNewId ::</span> <span class="dt">MonadState</span> <span class="dt">TransactionId</span> m <span class="ot">=&gt;</span> m <span class="dt">TransactionId</span></span>
<span id="cb23-2"><a href="#cb23-2"></a>getNewId <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb23-3"><a href="#cb23-3"></a> newId <span class="ot">&lt;-</span> get</span>
<span id="cb23-4"><a href="#cb23-4"></a> put (<span class="fu">succ</span> newId)</span>
<span id="cb23-5"><a href="#cb23-5"></a> <span class="fu">return</span> newId</span></code></pre></div>
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1"></a><span class="ot">registerPayment ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">TransactionId</span> <span class="dt">Transaction</span></span>
<span id="cb24-2"><a href="#cb24-2"></a>registerPayment price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb24-3"><a href="#cb24-3"></a> newId <span class="ot">&lt;-</span> getNewId</span>
<span id="cb24-4"><a href="#cb24-4"></a> <span class="fu">return</span> <span class="dt">Transaction</span></span>
<span id="cb24-5"><a href="#cb24-5"></a> { transactionId <span class="ot">=</span> newId</span>
<span id="cb24-6"><a href="#cb24-6"></a> transactionAmount <span class="ot">=</span> price</span>
<span id="cb24-7"><a href="#cb24-7"></a> }</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="monaderror">MonadError</h2>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadError</span> e m <span class="kw">where</span></span>
<span id="cb25-2"><a href="#cb25-2"></a><span class="ot"> throwError ::</span> e <span class="ot">-&gt;</span> m a</span>
<span id="cb25-3"><a href="#cb25-3"></a><span class="ot"> catchError ::</span> m a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> m a) <span class="ot">-&gt;</span> m a</span></code></pre></div>
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1"></a><span class="kw">data</span> <span class="dt">Either</span> e a <span class="ot">=</span> <span class="dt">Left</span> e <span class="op">|</span> <span class="dt">Right</span> a</span>
<span id="cb26-2"><a href="#cb26-2"></a></span>
<span id="cb26-3"><a href="#cb26-3"></a><span class="kw">instance</span> <span class="dt">MonadError</span> e (<span class="dt">Either</span> e) <span class="kw">where</span></span>
<span id="cb26-4"><a href="#cb26-4"></a> throwError e <span class="ot">=</span> <span class="dt">Left</span> e</span>
<span id="cb26-5"><a href="#cb26-5"></a></span>
<span id="cb26-6"><a href="#cb26-6"></a> catchError (<span class="dt">Left</span> e) f <span class="ot">=</span> f e</span>
<span id="cb26-7"><a href="#cb26-7"></a> catchError (<span class="dt">Right</span> a) _ <span class="ot">=</span> <span class="dt">Right</span> a</span></code></pre></div>
</section>
<section class="slide level1">
<p>Мы хотим:</p>
<ol type="1">
<li class="fragment"><del>Отделить эффекты от конкретной монады</del></li>
<li class="fragment">Получить возможность комбинировать разные эффекты</li>
</ol>
</section>
<section class="slide level1">
<p>Начнем с функторов</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1"></a><span class="kw">data</span> <span class="dt">Compose</span> f g a <span class="ot">=</span> <span class="dt">Compose</span> {<span class="ot"> getCompose ::</span> f (g a) }</span></code></pre></div>
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1"></a><span class="kw">type</span> <span class="dt">ErrorStateFunctor</span> a <span class="ot">=</span></span>
<span id="cb28-2"><a href="#cb28-2"></a> <span class="dt">Compose</span> (<span class="dt">Either</span> <span class="dt">PaymentError</span>) (<span class="dt">State</span> <span class="dt">TransactionId</span>) a</span></code></pre></div>
<div class="sourceCode" id="cb29"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1"></a><span class="co">-- Compose</span></span>
<span id="cb29-2"><a href="#cb29-2"></a><span class="co">-- { getCompose ::</span></span>
<span id="cb29-3"><a href="#cb29-3"></a><span class="co">-- Either PaymentError (State TransactionId a)</span></span>
<span id="cb29-4"><a href="#cb29-4"></a><span class="co">-- }</span></span></code></pre></div>
<div class="sourceCode" id="cb30"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1"></a><span class="kw">instance</span> (<span class="dt">Functor</span> f, <span class="dt">Functor</span> g) <span class="ot">=&gt;</span><span class="dt">Functor</span> (<span class="dt">Compose</span> f g) <span class="kw">where</span></span>
<span id="cb30-2"><a href="#cb30-2"></a> <span class="fu">fmap</span> f (<span class="dt">Compose</span> x) <span class="ot">=</span> <span class="dt">Compose</span> (<span class="fu">fmap</span> (<span class="fu">fmap</span> f) x)</span></code></pre></div>
<p><span class="fragment">🎉</span></p>
<p><span class="fragment">(<code>Applicative</code> тоже можно можете сами попробовать)</span></p>
</section>
<section class="slide level1">
<p>К монадам!</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1"></a><span class="kw">instance</span> (<span class="dt">Monad</span> f, <span class="dt">Monad</span> g) <span class="ot">=&gt;</span> <span class="dt">Monad</span> (<span class="dt">Compose</span> f g) <span class="kw">where</span></span>
<span id="cb31-2"><a href="#cb31-2"></a> <span class="fu">return</span> x <span class="ot">=</span> <span class="dt">Compose</span> (<span class="fu">return</span> (<span class="fu">return</span> x))</span>
<span id="cb31-3"><a href="#cb31-3"></a> (<span class="dt">Compose</span> x) <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> <span class="op">???</span></span></code></pre></div>
<p><span class="fragment">😢</span></p>
<p><span class="fragment">Все равно хочется!</span></p>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb32"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1"></a><span class="kw">data</span> <span class="dt">Compose</span> f g a <span class="ot">=</span> <span class="dt">Compose</span> {<span class="ot"> getCompose ::</span> f (g a) }</span></code></pre></div>
<p><span class="fragment">Для такого не можем</span></p>
<div class="sourceCode" id="cb33"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1"></a><span class="kw">data</span> <span class="dt">ErrorState</span> e s a <span class="ot">=</span></span>
<span id="cb33-2"><a href="#cb33-2"></a> <span class="dt">ErrorState</span> {<span class="ot"> runErrorState ::</span> <span class="dt">State</span> s (<span class="dt">Either</span> e a) }</span></code></pre></div>
<p><span class="fragment">А для такого можем!</span></p>
<div class="sourceCode" id="cb34"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb34-1"><a href="#cb34-1"></a>(<span class="dt">State</span> s (<span class="dt">Either</span> e a)) <span class="op">~</span> (s <span class="ot">-&gt;</span> <span class="dt">Either</span> e (a, s))</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="#cb35-1"></a><span class="kw">data</span> <span class="dt">ErrorState</span> e s a <span class="ot">=</span></span>
<span id="cb35-2"><a href="#cb35-2"></a> <span class="dt">ErrorState</span> {<span class="ot"> runErrorState ::</span> <span class="dt">State</span> s (<span class="dt">Either</span> e a) }</span></code></pre></div>
<p><span class="fragment">Хочется чтобы можно было не только <code>Either</code>!</span></p>
<div class="sourceCode" id="cb36"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb37"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb37-1"><a href="#cb37-1"></a><span class="kw">data</span> <span class="dt">StateT</span> s m a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> m (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb38"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb38-1"><a href="#cb38-1"></a><span class="kw">instance</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span> <span class="dt">Monad</span> (<span class="dt">StateT</span> s m) <span class="kw">where</span></span>
<span id="cb38-2"><a href="#cb38-2"></a> <span class="fu">return</span> a <span class="ot">=</span> <span class="dt">StateT</span> <span class="op">$</span> \ s <span class="ot">-&gt;</span> <span class="fu">return</span> (a, s)</span>
<span id="cb38-3"><a href="#cb38-3"></a></span>
<span id="cb38-4"><a href="#cb38-4"></a> m <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> <span class="dt">StateT</span> (\s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb38-5"><a href="#cb38-5"></a> (a, s&#39;) <span class="ot">&lt;-</span> runStateT m s</span>
<span id="cb38-6"><a href="#cb38-6"></a> runStateT (f a) s&#39;</span>
<span id="cb38-7"><a href="#cb38-7"></a> )</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="transformers">Transformers!</h2>
<p><img data-src="images/transformer.gif" height="400" /></p>
</section>
<section class="slide level1">
<h2 id="вернем-операции">Вернем операции!</h2>
<div class="sourceCode" id="cb39"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb39-1"><a href="#cb39-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadState</span> s m <span class="kw">where</span></span>
<span id="cb39-2"><a href="#cb39-2"></a><span class="ot"> get ::</span> m s</span>
<span id="cb39-3"><a href="#cb39-3"></a><span class="ot"> put ::</span> s <span class="ot">-&gt;</span> m ()</span></code></pre></div>
<div class="sourceCode" id="cb40"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb40-1"><a href="#cb40-1"></a><span class="kw">data</span> <span class="dt">StateT</span> s n a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> n (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb41"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb41-1"><a href="#cb41-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> n <span class="ot">=&gt;</span> <span class="dt">MonadState</span> s (<span class="dt">StateT</span> s n) <span class="kw">where</span></span>
<span id="cb41-2"><a href="#cb41-2"></a> get <span class="ot">=</span> <span class="dt">StateT</span> (\s <span class="ot">-&gt;</span> <span class="fu">return</span> (s, s))</span>
<span id="cb41-3"><a href="#cb41-3"></a> put s <span class="ot">=</span> <span class="dt">StateT</span> (\_ <span class="ot">-&gt;</span> <span class="fu">return</span> ((), s)</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="error">Error</h2>
<div class="sourceCode" id="cb42"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb42-1"><a href="#cb42-1"></a><span class="kw">data</span> <span class="dt">ExceptT</span> e n a <span class="ot">=</span> <span class="dt">ExceptT</span> {<span class="ot"> runExceptT ::</span> n (<span class="dt">Either</span> e a) }</span></code></pre></div>
<div class="sourceCode" id="cb43"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb43-1"><a href="#cb43-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadError</span> e m <span class="kw">where</span></span>
<span id="cb43-2"><a href="#cb43-2"></a><span class="ot"> throwError ::</span> e <span class="ot">-&gt;</span> m a</span>
<span id="cb43-3"><a href="#cb43-3"></a><span class="ot"> catchError ::</span> m a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> m a) <span class="ot">-&gt;</span> m a</span></code></pre></div>
<div class="sourceCode" id="cb44"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb44-1"><a href="#cb44-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> n <span class="ot">=&gt;</span> <span class="dt">MonadError</span> e (<span class="dt">ExceptT</span> e n) <span class="kw">where</span></span>
<span id="cb44-2"><a href="#cb44-2"></a> throwError e <span class="ot">=</span> <span class="dt">ExceptT</span> (<span class="fu">return</span> (<span class="dt">Left</span> e))</span>
<span id="cb44-3"><a href="#cb44-3"></a></span>
<span id="cb44-4"><a href="#cb44-4"></a> catchError (<span class="dt">ExceptT</span> n) f <span class="ot">=</span> <span class="dt">ExceptT</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb44-5"><a href="#cb44-5"></a> x <span class="ot">&lt;-</span> n</span>
<span id="cb44-6"><a href="#cb44-6"></a> <span class="kw">case</span> x <span class="kw">of</span></span>
<span id="cb44-7"><a href="#cb44-7"></a> <span class="dt">Left</span> e <span class="ot">-&gt;</span> runExceptT (f e)</span>
<span id="cb44-8"><a href="#cb44-8"></a> <span class="dt">Right</span> a <span class="ot">-&gt;</span> <span class="fu">return</span> (<span class="dt">Right</span> a)</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb45"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb45-1"><a href="#cb45-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadError</span> e m <span class="kw">where</span></span>
<span id="cb45-2"><a href="#cb45-2"></a><span class="ot"> throwError ::</span> e <span class="ot">-&gt;</span> m a</span>
<span id="cb45-3"><a href="#cb45-3"></a><span class="ot"> catchError ::</span> m a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> m a) <span class="ot">-&gt;</span> m a</span></code></pre></div>
<div class="sourceCode" id="cb46"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb46-1"><a href="#cb46-1"></a><span class="kw">data</span> <span class="dt">PaymentError</span> <span class="ot">=</span> <span class="dt">InsufficientBalance</span></span>
<span id="cb46-2"><a href="#cb46-2"></a></span>
<span id="cb46-3"><a href="#cb46-3"></a><span class="ot">pay ::</span> <span class="dt">MonadError</span> e m <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m <span class="dt">Balance</span></span>
<span id="cb46-4"><a href="#cb46-4"></a>pay balance price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb46-5"><a href="#cb46-5"></a> <span class="kw">let</span> newBalance <span class="ot">=</span> balance <span class="op">-</span> price</span>
<span id="cb46-6"><a href="#cb46-6"></a> when (newBalance <span class="op">&lt;</span> <span class="dv">0</span>) (throwError <span class="dt">InsufficientBalance</span>)</span>
<span id="cb46-7"><a href="#cb46-7"></a> <span class="fu">return</span> newBalance</span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="the-states">The states</h2>
<div class="sourceCode" id="cb47"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb47-1"><a href="#cb47-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb48"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb48-1"><a href="#cb48-1"></a><span class="kw">data</span> <span class="dt">StateT</span> s m a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> m (a, s) }</span></code></pre></div>
<p><span class="fragment">🤔</span></p>
</section>
<section class="slide level1">
<p>Напоминалочка:</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb49-1"><a href="#cb49-1"></a><span class="kw">data</span> <span class="dt">Identity</span> a <span class="ot">=</span> <span class="dt">Identity</span> {<span class="ot"> runIdentity ::</span> a }</span></code></pre></div>
<div class="sourceCode" id="cb50"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb50-1"><a href="#cb50-1"></a>(<span class="dt">Identity</span> a) <span class="op">~</span> a</span></code></pre></div>
<div class="sourceCode" id="cb51"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb51-1"><a href="#cb51-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span>
<span id="cb51-2"><a href="#cb51-2"></a></span>
<span id="cb51-3"><a href="#cb51-3"></a><span class="kw">data</span> <span class="dt">StateT</span> s m a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> m (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb52"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb52-1"><a href="#cb52-1"></a>(<span class="dt">StateT</span> s <span class="dt">Identity</span> a) <span class="op">~</span> (s <span class="ot">-&gt;</span> <span class="dt">Identity</span> (a, s))</span></code></pre></div>
<p><span class="fragment">🤔</span></p>
<div class="sourceCode" id="cb53"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb53-1"><a href="#cb53-1"></a>(s <span class="ot">-&gt;</span> <span class="dt">Identity</span> (a, s)) <span class="op">~</span> (s <span class="ot">-&gt;</span> (a, s)) <span class="op">~</span> (<span class="dt">State</span> s a)</span></code></pre></div>
<div class="sourceCode" id="cb54"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb54-1"><a href="#cb54-1"></a><span class="kw">type</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">StateT</span> s <span class="dt">Identity</span> a</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb55"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb55-1"><a href="#cb55-1"></a><span class="kw">data</span> <span class="dt">ExceptT</span> e n a <span class="ot">=</span> <span class="dt">ExceptT</span> {<span class="ot"> runExceptT ::</span> n (<span class="dt">Either</span> e a) }</span>
<span id="cb55-2"><a href="#cb55-2"></a></span>
<span id="cb55-3"><a href="#cb55-3"></a><span class="kw">data</span> <span class="dt">StateT</span> s m a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> m (a, s) }</span>
<span id="cb55-4"><a href="#cb55-4"></a></span>
<span id="cb55-5"><a href="#cb55-5"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadError</span> e m <span class="kw">where</span></span>
<span id="cb55-6"><a href="#cb55-6"></a><span class="ot"> throwError ::</span> e <span class="ot">-&gt;</span> m a</span>
<span id="cb55-7"><a href="#cb55-7"></a><span class="ot"> catchError ::</span> m a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> m a) <span class="ot">-&gt;</span> m a</span>
<span id="cb55-8"><a href="#cb55-8"></a></span>
<span id="cb55-9"><a href="#cb55-9"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">MonadState</span> s m <span class="kw">where</span></span>
<span id="cb55-10"><a href="#cb55-10"></a><span class="ot"> get ::</span> m s</span>
<span id="cb55-11"><a href="#cb55-11"></a><span class="ot"> put ::</span> s <span class="ot">-&gt;</span> m ()</span></code></pre></div>
<p>Пришли к тому, с чего начинали, только еще сложнее</p>
</section>
<section class="slide level1">
<ol type="1">
<li class="fragment"><del>Отделить эффекты от конкретной монады</del></li>
<li class="fragment">Получить возможность комбинировать разные эффекты</li>
</ol>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb56"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb56-1"><a href="#cb56-1"></a><span class="ot">foo ::</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) <span class="dt">Int</span></span>
<span id="cb56-2"><a href="#cb56-2"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb56-3"><a href="#cb56-3"></a> c <span class="ot">&lt;-</span> get <span class="co">-- :: State Char Char</span></span>
<span id="cb56-4"><a href="#cb56-4"></a> throwError <span class="dt">True</span> <span class="co">-- :: ExceptT Bool (State Char) Int</span></span></code></pre></div>
<div class="sourceCode" id="cb57"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb57-1"><a href="#cb57-1"></a><span class="ot">(&gt;=&gt;) ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> (b <span class="ot">-&gt;</span> m c) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m c)</span>
<span id="cb57-2"><a href="#cb57-2"></a></span>
<span id="cb57-3"><a href="#cb57-3"></a><span class="co">-- Такого нет</span></span>
<span id="cb57-4"><a href="#cb57-4"></a>(<span class="op">&gt;=&gt;</span>)</span>
<span id="cb57-5"><a href="#cb57-5"></a><span class="ot"> ::</span> (<span class="dt">Monad</span> m, <span class="dt">Monad</span> n)</span>
<span id="cb57-6"><a href="#cb57-6"></a> <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> (b <span class="ot">-&gt;</span> n c) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="op">?</span> c)</span></code></pre></div>
<div class="sourceCode" id="cb58"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb58-1"><a href="#cb58-1"></a><span class="ot">lift ::</span> <span class="dt">State</span> <span class="dt">Char</span> a <span class="ot">-&gt;</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) a</span></code></pre></div>
<div class="sourceCode" id="cb59"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb59-1"><a href="#cb59-1"></a><span class="ot">foo ::</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) <span class="dt">Int</span></span>
<span id="cb59-2"><a href="#cb59-2"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb59-3"><a href="#cb59-3"></a> c <span class="ot">&lt;-</span> lift get <span class="co">-- :: ExceptT Bool (State Char) Int</span></span>
<span id="cb59-4"><a href="#cb59-4"></a> throwError <span class="dt">True</span> <span class="co">-- :: ExceptT Bool (State Char) Int</span></span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb60"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb60-1"><a href="#cb60-1"></a><span class="kw">class</span> <span class="dt">MonadTrans</span> t <span class="kw">where</span></span>
<span id="cb60-2"><a href="#cb60-2"></a><span class="ot"> lift ::</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span> m a <span class="ot">-&gt;</span> t m a</span></code></pre></div>
<div class="sourceCode" id="cb61"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb61-1"><a href="#cb61-1"></a><span class="ot">lift ::</span> <span class="dt">State</span> <span class="dt">Char</span> a <span class="ot">-&gt;</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) a</span>
<span id="cb61-2"><a href="#cb61-2"></a><span class="co">-- (m ) a -&gt; (t ) (m ) a</span></span></code></pre></div>
<div class="sourceCode" id="cb62"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb62-1"><a href="#cb62-1"></a><span class="kw">instance</span> <span class="dt">MonadTrans</span> (<span class="dt">StateT</span> s) <span class="kw">where</span></span>
<span id="cb62-2"><a href="#cb62-2"></a> lift m <span class="ot">=</span> <span class="dt">StateT</span> <span class="op">$</span> \ s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb62-3"><a href="#cb62-3"></a> a <span class="ot">&lt;-</span> m</span>
<span id="cb62-4"><a href="#cb62-4"></a> <span class="fu">return</span> (a, s)</span></code></pre></div>
<div class="sourceCode" id="cb63"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb63-1"><a href="#cb63-1"></a><span class="kw">instance</span> <span class="dt">MonadTrans</span> (<span class="dt">ExceptT</span> e) <span class="kw">where</span></span>
<span id="cb63-2"><a href="#cb63-2"></a> lift m <span class="ot">=</span> <span class="dt">ExceptT</span> (<span class="fu">fmap</span> <span class="dt">Right</span> m)</span></code></pre></div>
<div class="sourceCode" id="cb64"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb64-1"><a href="#cb64-1"></a><span class="ot">foo ::</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) <span class="dt">Int</span></span>
<span id="cb64-2"><a href="#cb64-2"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb64-3"><a href="#cb64-3"></a> c <span class="ot">&lt;-</span> lift get</span>
<span id="cb64-4"><a href="#cb64-4"></a> throwError <span class="dt">True</span></span></code></pre></div>
</section>
<section class="slide level1">
<p>Но хочется чтобы без <code>lift</code> 🙂</p>
<div class="sourceCode" id="cb65"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb65-1"><a href="#cb65-1"></a><span class="ot">foo ::</span> <span class="dt">ExceptT</span> <span class="dt">Bool</span> (<span class="dt">State</span> <span class="dt">Char</span>) <span class="dt">Int</span></span>
<span id="cb65-2"><a href="#cb65-2"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb65-3"><a href="#cb65-3"></a> c <span class="ot">&lt;-</span> get</span>
<span id="cb65-4"><a href="#cb65-4"></a> throwError <span class="dt">True</span></span></code></pre></div>
<p><span class="fragment">Нужен инстанс <code>MonadState</code> для <code>ExceptT</code></span></p>
<div class="sourceCode" id="cb66"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb66-1"><a href="#cb66-1"></a><span class="kw">instance</span> <span class="dt">MonadState</span> s n <span class="ot">=&gt;</span> <span class="dt">MonadState</span> s (<span class="dt">ExceptT</span> e n) <span class="kw">where</span></span>
<span id="cb66-2"><a href="#cb66-2"></a> get <span class="ot">=</span> lift get</span>
<span id="cb66-3"><a href="#cb66-3"></a> put s <span class="ot">=</span> lift (put s)</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb67"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb67-1"><a href="#cb67-1"></a>registerPayment</span>
<span id="cb67-2"><a href="#cb67-2"></a><span class="ot"> ::</span> <span class="dt">State</span> <span class="dt">TransactionId</span> m</span>
<span id="cb67-3"><a href="#cb67-3"></a> <span class="ot">=&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m <span class="dt">Transaction</span></span>
<span id="cb67-4"><a href="#cb67-4"></a>pay</span>
<span id="cb67-5"><a href="#cb67-5"></a><span class="ot"> ::</span> <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m</span>
<span id="cb67-6"><a href="#cb67-6"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m <span class="dt">Balance</span></span></code></pre></div>
<div class="sourceCode" id="cb68"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb68-1"><a href="#cb68-1"></a>payAndRegister</span>
<span id="cb68-2"><a href="#cb68-2"></a><span class="ot"> ::</span> (<span class="dt">State</span> <span class="dt">TransactionId</span> m, <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m)</span>
<span id="cb68-3"><a href="#cb68-3"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span>
<span id="cb68-4"><a href="#cb68-4"></a>payAndRegister balance price <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb68-5"><a href="#cb68-5"></a> newBalance <span class="ot">&lt;-</span> pay balance price</span>
<span id="cb68-6"><a href="#cb68-6"></a> transacation <span class="ot">&lt;-</span> registerPayment price</span>
<span id="cb68-7"><a href="#cb68-7"></a> <span class="fu">return</span> (newBalance, transaction)</span></code></pre></div>
</section>
<section class="slide level1">
<p>Как это “запускать”?</p>
<div class="sourceCode" id="cb69"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb69-1"><a href="#cb69-1"></a>payAndRegister</span>
<span id="cb69-2"><a href="#cb69-2"></a><span class="ot"> ::</span> (<span class="dt">State</span> <span class="dt">TransactionId</span> m, <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m)</span>
<span id="cb69-3"><a href="#cb69-3"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span></code></pre></div>
<div class="sourceCode" id="cb70"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb70-1"><a href="#cb70-1"></a><span class="ot">myBalance ::</span> <span class="dt">Balance</span></span>
<span id="cb70-2"><a href="#cb70-2"></a><span class="ot">myPrice ::</span> <span class="dt">Price</span></span>
<span id="cb70-3"><a href="#cb70-3"></a></span>
<span id="cb70-4"><a href="#cb70-4"></a>balanceAndTransaction</span>
<span id="cb70-5"><a href="#cb70-5"></a><span class="ot"> ::</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span></code></pre></div>
<div class="sourceCode" id="cb71"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb71-1"><a href="#cb71-1"></a><span class="kw">data</span> <span class="dt">ExceptT</span> e n a <span class="ot">=</span> <span class="dt">ExceptT</span> {<span class="ot"> runExceptT ::</span> n (<span class="dt">Either</span> e a) }</span>
<span id="cb71-2"><a href="#cb71-2"></a><span class="kw">data</span> <span class="dt">StateT</span> s n a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> n (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb72"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb72-1"><a href="#cb72-1"></a>balanceAndTransaction <span class="ot">=</span></span>
<span id="cb72-2"><a href="#cb72-2"></a> runStateT <span class="dv">0</span> (payAndRegister myBalance myPrice)</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb73"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb73-1"><a href="#cb73-1"></a>payAndRegister</span>
<span id="cb73-2"><a href="#cb73-2"></a><span class="ot"> ::</span> (<span class="dt">State</span> <span class="dt">TransactionId</span> m, <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m)</span>
<span id="cb73-3"><a href="#cb73-3"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span>
<span id="cb73-4"><a href="#cb73-4"></a></span>
<span id="cb73-5"><a href="#cb73-5"></a><span class="kw">data</span> <span class="dt">StateT</span> s n a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> n (a, s) }</span></code></pre></div>
<div class="sourceCode" id="cb74"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb74-1"><a href="#cb74-1"></a>balanceAndTransaction</span>
<span id="cb74-2"><a href="#cb74-2"></a><span class="ot"> ::</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span>
<span id="cb74-3"><a href="#cb74-3"></a>balanceAndTransaction <span class="ot">=</span></span>
<span id="cb74-4"><a href="#cb74-4"></a> <span class="fu">flip</span> runStateT <span class="dv">0</span> (payAndRegister myBalance myPrice)</span></code></pre></div>
<div class="sourceCode" id="cb75"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb75-1"><a href="#cb75-1"></a> <span class="fu">flip</span> runStateT <span class="dv">0</span> (payAndRegister myBalance myPrice)</span>
<span id="cb75-2"><a href="#cb75-2"></a><span class="co">-- ^-------------^</span></span>
<span id="cb75-3"><a href="#cb75-3"></a><span class="co">-- StateT TransactionId n a -&gt; n a</span></span></code></pre></div>
<div class="sourceCode" id="cb76"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb76-1"><a href="#cb76-1"></a><span class="co">-- (n a) ~ (Either PaymentError (Balance, Transaction))</span></span></code></pre></div>
<div class="sourceCode" id="cb77"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb77-1"><a href="#cb77-1"></a><span class="fu">flip</span> runStateT <span class="dv">0</span> (payAndRegister myBalance myPrice)</span>
<span id="cb77-2"><a href="#cb77-2"></a><span class="co">-- ^--------------------------------^</span></span>
<span id="cb77-3"><a href="#cb77-3"></a><span class="co">-- StateT TransactionId</span></span>
<span id="cb77-4"><a href="#cb77-4"></a><span class="co">-- (Either PaymentError)</span></span>
<span id="cb77-5"><a href="#cb77-5"></a><span class="co">-- (Balance, Transaction)</span></span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb78"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb78-1"><a href="#cb78-1"></a>payAndRegister</span>
<span id="cb78-2"><a href="#cb78-2"></a><span class="ot"> ::</span> (<span class="dt">State</span> <span class="dt">TransactionId</span> m, <span class="dt">MonadError</span> <span class="dt">PaymentError</span> m)</span>
<span id="cb78-3"><a href="#cb78-3"></a> <span class="ot">=&gt;</span> <span class="dt">Balance</span> <span class="ot">-&gt;</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> m (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span>
<span id="cb78-4"><a href="#cb78-4"></a></span>
<span id="cb78-5"><a href="#cb78-5"></a><span class="kw">data</span> <span class="dt">ExceptT</span> e n a <span class="ot">=</span> <span class="dt">ExceptT</span> {<span class="ot"> runExceptT ::</span> n (<span class="dt">Either</span> e a) }</span>
<span id="cb78-6"><a href="#cb78-6"></a><span class="kw">data</span> <span class="dt">StateT</span> s n a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> n (a, s) }</span>
<span id="cb78-7"><a href="#cb78-7"></a><span class="kw">data</span> <span class="dt">Identity</span> a <span class="ot">=</span> <span class="dt">Identity</span> {<span class="ot"> runIdentity ::</span> a }</span></code></pre></div>
<div class="sourceCode" id="cb79"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb79-1"><a href="#cb79-1"></a>balanceAndTransaction</span>
<span id="cb79-2"><a href="#cb79-2"></a><span class="ot"> ::</span> <span class="dt">Either</span> <span class="dt">PaymentError</span> (<span class="dt">Balance</span>, <span class="dt">Transaction</span>)</span>
<span id="cb79-3"><a href="#cb79-3"></a>balanceAndTransaction <span class="ot">=</span></span>
<span id="cb79-4"><a href="#cb79-4"></a> (runIdentity <span class="op">.</span> runExceptT <span class="op">.</span> <span class="fu">flip</span> runStateT <span class="dv">0</span>)</span>
<span id="cb79-5"><a href="#cb79-5"></a> (payAndRegister myBalance myPrice)</span></code></pre></div>
</section>
<section class="slide level1">
<p>А теперь мы пойдем в совершенно другом направлении!</p>
</section>
<section class="slide level1">
<h2 id="напоминалочка-1">Напоминалочка</h2>
<div class="sourceCode" id="cb80"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb80-1"><a href="#cb80-1"></a><span class="kw">class</span> <span class="dt">Show</span> a <span class="kw">where</span></span>
<span id="cb80-2"><a href="#cb80-2"></a><span class="ot"> show ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span></code></pre></div>
<div class="sourceCode" id="cb81"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb81-1"><a href="#cb81-1"></a><span class="kw">data</span> <span class="dt">Foo</span> <span class="ot">=</span> <span class="dt">Bar</span> {<span class="ot"> barInt ::</span> <span class="dt">Int</span> }</span>
<span id="cb81-2"><a href="#cb81-2"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
<div class="sourceCode" id="cb82"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb82-1"><a href="#cb82-1"></a><span class="fu">show</span> (<span class="dt">Bar</span> <span class="dv">8</span>)</span>
<span id="cb82-2"><a href="#cb82-2"></a><span class="co">-- Bar {barInt = 8}</span></span></code></pre></div>
</section>
<section class="slide level1">
<h2 id="read">Read</h2>
<p>Обратная операция к <code>show</code></p>
<div class="sourceCode" id="cb83"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb83-1"><a href="#cb83-1"></a><span class="fu">read</span><span class="ot"> ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a</span></code></pre></div>
<div class="sourceCode" id="cb84"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb84-1"><a href="#cb84-1"></a><span class="kw">class</span> <span class="dt">Read</span> a <span class="kw">where</span></span>
<span id="cb84-2"><a href="#cb84-2"></a> <span class="fu">readsPrec</span></span>
<span id="cb84-3"><a href="#cb84-3"></a><span class="ot"> ::</span> <span class="co">-- | Приоритет контекста выражения</span></span>
<span id="cb84-4"><a href="#cb84-4"></a> <span class="dt">Int</span></span>
<span id="cb84-5"><a href="#cb84-5"></a> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb84-6"><a href="#cb84-6"></a> <span class="ot">-&gt;</span> [(a, <span class="dt">String</span>)]</span></code></pre></div>
<div class="sourceCode" id="cb85"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb85-1"><a href="#cb85-1"></a><span class="kw">data</span> <span class="dt">Foo</span> <span class="ot">=</span> <span class="dt">Bar</span> {<span class="ot"> barInt ::</span> <span class="dt">Int</span> }</span>
<span id="cb85-2"><a href="#cb85-2"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Read</span>)</span></code></pre></div>
<div class="sourceCode" id="cb86"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb86-1"><a href="#cb86-1"></a><span class="fu">read</span> <span class="st">&quot;Bar {barInt = 8}&quot;</span></span>
<span id="cb86-2"><a href="#cb86-2"></a><span class="co">-- Bar { barInt = 8 }</span></span></code></pre></div>
</section>
<section id="монады" class="slide level1">
<h1>Монады</h1>
<ol type="1">
<li class="fragment">Базовые операции монады (эффекты)</li>
</ol>
<p><span class="fragment"><code>MonadState</code>, <code>MonadErrror</code></span></p>
<ol start="2" type="1">
<li class="fragment">Конкретные монады (переносчик) (и способы их “разворачивать”)</li>
</ol>
<p><span class="fragment"><code>StateT</code> (<code>runStateT</code>), <code>Either</code>, <code>ExceptT</code> (<code>runExceptT</code>)</span></p>
<p><span class="fragment">Переводят эффекты в pure код</span></p>
</section>
<section id="монада-io" class="slide level1">
<h1>Монада <code>IO</code></h1>
<p><span class="fragment">Обладает только базовыми операциями</span> <span class="fragment">(Невозможно перевести в pure код)</span></p>
<div class="sourceCode" id="cb87"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb87-1"><a href="#cb87-1"></a><span class="fu">getLine</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb87-2"><a href="#cb87-2"></a></span>
<span id="cb87-3"><a href="#cb87-3"></a><span class="fu">putStrLn</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span></code></pre></div>
<div class="sourceCode" id="cb88"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb88-1"><a href="#cb88-1"></a><span class="kw">type</span> <span class="dt">FilePath</span> <span class="ot">=</span> <span class="dt">String</span></span>
<span id="cb88-2"><a href="#cb88-2"></a></span>
<span id="cb88-3"><a href="#cb88-3"></a><span class="fu">readFile</span><span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb88-4"><a href="#cb88-4"></a></span>
<span id="cb88-5"><a href="#cb88-5"></a><span class="fu">writeFile</span><span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span></code></pre></div>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb89"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb89-1"><a href="#cb89-1"></a><span class="ot">add10FromConsole ::</span> <span class="dt">IO</span> ()</span>
<span id="cb89-2"><a href="#cb89-2"></a>add10FromConsole <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb89-3"><a href="#cb89-3"></a> x <span class="ot">&lt;-</span> <span class="fu">getLine</span></span>
<span id="cb89-4"><a href="#cb89-4"></a> <span class="kw">let</span></span>
<span id="cb89-5"><a href="#cb89-5"></a><span class="ot"> n ::</span> <span class="dt">Int</span></span>
<span id="cb89-6"><a href="#cb89-6"></a> n <span class="ot">=</span> <span class="fu">read</span> x</span>
<span id="cb89-7"><a href="#cb89-7"></a> <span class="fu">putStrLn</span> (<span class="fu">show</span> (n <span class="op">+</span> <span class="dv">10</span>))</span></code></pre></div>
</section>
<section class="slide level1">
<p>“Разворачивать” <code>IO</code> умеет только рантайм.</p>
<div class="sourceCode" id="cb90"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb90-1"><a href="#cb90-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb90-2"><a href="#cb90-2"></a>main <span class="ot">=</span> add10FromConsole</span></code></pre></div>
<pre class="fragment"><code>&gt; 10
20</code></pre>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb92"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb92-1"><a href="#cb92-1"></a><span class="co">-- Как &#39;read&#39;, но не взрывается в рантайме</span></span>
<span id="cb92-2"><a href="#cb92-2"></a><span class="ot">readMaybe ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span></code></pre></div>
<div class="sourceCode" id="cb93"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb93-1"><a href="#cb93-1"></a><span class="ot">accumulateNums ::</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> ()</span>
<span id="cb93-2"><a href="#cb93-2"></a>accumulateNums <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb93-3"><a href="#cb93-3"></a> x <span class="ot">&lt;-</span> lift <span class="fu">getLine</span></span>
<span id="cb93-4"><a href="#cb93-4"></a> <span class="kw">case</span> (readMaybe<span class="ot"> x ::</span> <span class="dt">Int</span>) <span class="kw">of</span></span>
<span id="cb93-5"><a href="#cb93-5"></a> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb93-6"><a href="#cb93-6"></a> s <span class="ot">&lt;-</span> get</span>
<span id="cb93-7"><a href="#cb93-7"></a> lift (<span class="fu">putStrLn</span> (<span class="fu">show</span> s))</span>
<span id="cb93-8"><a href="#cb93-8"></a> <span class="dt">Just</span> x&#39; <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb93-9"><a href="#cb93-9"></a> modify (<span class="op">+</span> x&#39;)</span>
<span id="cb93-10"><a href="#cb93-10"></a> accumulateNums</span></code></pre></div>
<div class="sourceCode" id="cb94"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb94-1"><a href="#cb94-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb94-2"><a href="#cb94-2"></a>main <span class="ot">=</span> <span class="fu">flip</span> runStateT <span class="dv">0</span> accumulateNums</span></code></pre></div>
<pre class="fragment"><code>&gt; 8
&gt; 3
&gt; a
11</code></pre>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb96"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb96-1"><a href="#cb96-1"></a><span class="ot">accumulateNums ::</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> ()</span></code></pre></div>
<div class="sourceCode" id="cb97"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb97-1"><a href="#cb97-1"></a><span class="co">-- Хочется так, но где тут взять &#39;IO&#39;?</span></span>
<span id="cb97-2"><a href="#cb97-2"></a><span class="ot">accumulateNums ::</span> <span class="dt">MonadState</span> <span class="dt">Int</span> m <span class="ot">=&gt;</span> m ()</span></code></pre></div>
<p><span class="fragment">Трансформера <code>IO</code> нет.</span></p>
<p><span class="fragment">Тогда <code>lift</code>!</span></p>
<p><span class="fragment">Но <code>lift</code> поднимает строго на один уровень.</span></p>
</section>
<section class="slide level1">
<div class="sourceCode" id="cb98"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb98-1"><a href="#cb98-1"></a><span class="kw">class</span> <span class="dt">MonadIO</span> m <span class="kw">where</span></span>
<span id="cb98-2"><a href="#cb98-2"></a><span class="ot"> liftIO ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> m a</span></code></pre></div>
<div class="sourceCode" id="cb99"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb99-1"><a href="#cb99-1"></a><span class="ot">accumulateNums ::</span> (<span class="dt">MonadState</span> <span class="dt">Int</span> m, <span class="dt">MonadIO</span> m) <span class="ot">=&gt;</span> m ()</span>
<span id="cb99-2"><a href="#cb99-2"></a>accumulateNums <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb99-3"><a href="#cb99-3"></a> x <span class="ot">&lt;-</span> liftIO <span class="fu">getLine</span></span>
<span id="cb99-4"><a href="#cb99-4"></a> <span class="kw">case</span> (readMaybe<span class="ot"> x ::</span> <span class="dt">Int</span>) <span class="kw">of</span></span>
<span id="cb99-5"><a href="#cb99-5"></a> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb99-6"><a href="#cb99-6"></a> s <span class="ot">&lt;-</span> get</span>
<span id="cb99-7"><a href="#cb99-7"></a> liftIO (<span class="fu">putStrLn</span> (<span class="fu">show</span> s))</span>
<span id="cb99-8"><a href="#cb99-8"></a> <span class="dt">Just</span> x&#39; <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb99-9"><a href="#cb99-9"></a> modify (<span class="op">+</span> x&#39;)</span>
<span id="cb99-10"><a href="#cb99-10"></a> accumulateNums</span></code></pre></div>
<div class="sourceCode" id="cb100"><pre class="sourceCode haskell fragment"><code class="sourceCode haskell"><span id="cb100-1"><a href="#cb100-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb100-2"><a href="#cb100-2"></a>main <span class="ot">=</span> <span class="fu">flip</span> runStateT <span class="dv">0</span> accumulateNums</span></code></pre></div>
<pre class="fragment"><code>&gt; 8
&gt; 3
&gt; a
11</code></pre>
</section>
</div>
</div>
<script src="reveal.js/js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
// Push each slide change to the browser history
history: true,
// Optional reveal.js plugins
dependencies: [
{ src: 'reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'reveal.js/plugin/zoom-js/zoom.js', async: true },
{ src: 'reveal.js/plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>