Skip to content
Browse files

2013-09-06.2

  • Loading branch information...
1 parent 3d82bb8 commit 4df27ae9a5c0c0260e9ce481fb779dba211b841f @qnikst committed
Showing with 56 additions and 44 deletions.
  1. +18 −14 posts/2013-09-06-serialization-p1.html
  2. +19 −15 rss.xml
  3. +19 −15 tags/haskell.xml
View
32 posts/2013-09-06-serialization-p1.html
@@ -36,6 +36,10 @@
<h1>Сериализация структур данных в Haskell.<br /> Часть 1: типы данных <br /><small><strong>September 6, 2013</strong></small></h1>
</div>
+<div style="float:right; width:200px">
+<strong>Updates:</strong><br /> 2013-09-06: исправлены ошибки в тексте (спасибо qrilka)
+</div>
+
<p><em>У меня тут в черновиках завалялась старый пост про сериализацию стуктур данных в haskell, доводить её до ума и продолжать мне немного лень, но если будет интересно то могу продолжать. Изначально серия статей предполагалась одновременно с доведением до ума пакета <a href="https://github.com/qnikst/strictput">strictput</a></em></p>
<p>Этим постом я хочу начать небольшую серию статей про сериализацию данных в Haskell. и описание библиотек их реализующих.</p>
<h2 id="типы-данных">Типы данных</h2>
@@ -45,9 +49,9 @@ <h2 id="типы-данных">Типы данных</h2>
<li>Взаимодействие с внешним рантаймом, например FFI;</li>
<li>Взаимодействие с внешним миром (IPC, передача в сеть и т.д.)</li>
</ol>
-<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором в разных и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам по для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
+<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором — в разных, и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
<h3 id="c-интерфейс">‘C’ интерфейс</h3>
-<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
+<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель, размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
<p>struct iovec { void *iov_base; size_t iov_len; }</p>
<p>в некоторых типах данных можно использовать данный подход, что позволит повысить их производительность, но об этом будет сказано отдельно.</p>
<p>Данный интерфейс может быть изображен в haskell как (# Addr#,CSize #) но крайне не рекомендуется так делать, поскольку это сильно усложнит работу с данными, при этом не принося выгоды, поскольку во многих случаях компилятор может преобразовать структуру к виду аналогичному данному.</p>
@@ -55,10 +59,10 @@ <h3 id="c-интерфейс">‘C’ интерфейс</h3>
<h4 id="типы-haskell-соотвествующие-c-интерфейсу">Типы haskell соотвествующие C интерфейсу</h4>
<p>В haskell существуют следующие типы соответсующие указателям в C:</p>
<h5 id="addr">Addr#</h5>
-<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
+<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы с этим типом есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
<h5 id="ptr">Ptr</h5>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Ptr</span> a <span class="fu">=</span> <span class="dt">Ptr</span> (<span class="dt">Addr</span><span class="fu">#</span>)</code></pre>
-<p>Типизированная обертка над Addr (lifted, unpacked by default (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
+<p>Типизированная обертка над Addr (lifted, unpacked по умолчанию (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
<p>Функции для работы с указателями предоставляются модулем ‘Foreign.Ptr’</p>
<h5 id="foreignptr">ForeignPtr</h5>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">ForeignPtr</span> <span class="fu">=</span> <span class="dt">ForeignPtr</span> <span class="dt">Addr</span><span class="fu">#</span> <span class="dt">ForeignPtrConents</span></code></pre>
@@ -80,7 +84,7 @@ <h4 id="cstringcstring-len">CString/CString Len</h4>
</ul>
<h4 id="string">String</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">type</span> <span class="dt">String</span> <span class="fu">=</span> [<span class="dt">Char</span>]</code></pre>
-<p>Очень широко используемый тип данных для внутреннего представления тектовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто плохоиспользуется (missused). Поскольку структура данных является ленивой, то возможно создание бесконечных, и цикличеких списков, а так же итеративное построение списка.</p>
+<p>Очень широко используемый тип данных для внутреннего представления текcтовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто используется не по назначению. Поскольку структура данных является ленивой, то возможно создание бесконечных и цикличеких списков, а так же итеративное построение списка.</p>
<p>Характеристики:</p>
<ul>
<li>ленивый</li>
@@ -91,10 +95,10 @@ <h4 id="string">String</h4>
<li>высокий overhead по памяти для хранения списка (x+8+2)*n+8</li>
<li>очень низкая скорость работы</li>
<li>внутренний (не pinned тип)</li>
-<li>build/foldr deforestation</li>
-<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется не использовать LazyIO, а исполььзовать итеративные библиотеки такие как (pipes, conduit, itertee)</li>
+<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.646">build/foldr deforestation</a></li>
+<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется использовать не ленивый ввод-вывод, а итеративные библиотеки такие как pipes, conduit, или iteratee.</li>
</ul>
-<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это не необходимо, например в случаях если списки играют роль “клея” между операциями.</p>
+<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это без этого можно обойтись, например, в случаях, если списки играют роль “клея” между операциями,.</p>
<p>Операции над структурой данных:</p>
<ul>
<li>size: O(N) /N прыжков по памяти/ const по памяти</li>
@@ -105,7 +109,7 @@ <h4 id="string">String</h4>
<p>Все операции изменяющие структуру данных пересоздают структуру слева от списка.</p>
<h4 id="word8">[Word8]</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">data</span> [] a <span class="fu">=</span> [] <span class="fu">|</span> a <span class="fu">:</span> [a]</code></pre>
-<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету функционала работы с IO.</p>
+<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету возможностей работы с вводом выводом.</p>
<h4 id="text">Text</h4>
<p>Современный внутренний тип для предствления строковых данных. Однако рассмотрение данного типа выходит за рамки поста.</p>
<h4 id="bytestring">ByteString</h4>
@@ -119,9 +123,9 @@ <h4 id="bytestring">ByteString</h4>
<p>То, что каждый из блоков данных содержит указатель на начало выделенной памяти позволяет обходиться без дополнительного копирования структуры удаляя её в том случае, если на неё никто не ссылается.</p>
<h4 id="lazy-bytestring">Lazy ByteString</h4>
<p>data ByteString = Empty | Chunk !Internal.ByteString ByteString</p>
-<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие, внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
+<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие: внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
<h3 id="перевод-типов-данных-друг-в-друга">Перевод типов данных друг в друга</h3>
-<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга я привел абсолютно невоспринимаемую картинку: (кто хочет може предложить мне более адекватный вариант).</p>
+<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга, в конце поста я привел абсолютно невоспринимаемую картинку (кто хочет може предложить мне более адекватный вариант).</p>
<p>При переводе типов из одного в другой нужно следить за следующими вещами:</p>
<ol style="list-style-type: decimal">
<li>алгоритмическая сложность операции;</li>
@@ -129,9 +133,9 @@ <h3 id="перевод-типов-данных-друг-в-друга">Пере
<li>энергичность/ленивость операции;</li>
<li>безопасность операции.</li>
</ol>
-<p>С первым пунктом все важно, второй тоже важен так как агрессивное использование памяти существенно изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости и не может ли произойти каскадное “форсирование” вычислений в тот момент когда этого допускать нельзя.</p>
-<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её полная копия операции ‘useAs*’ в этом случае нужно понимать, что данный подход приводит к увеличению сложности и нагрузки на память.</p>
-<p><img src="../images/posts/parser-1/1.png" /></p>
+<p>С первым пунктом все важно, второй тоже важен, так как агрессивное использование памяти существенно может изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости, и не может ли произойти каскадное “форсирование” вычислений в тот момент, когда этого допускать нельзя.</p>
+<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры, так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её копия ‘useAs*’. В этом случае нужно понимать, что данный подход приводит к увеличению сложности алгоритма и дополнительной нагрузке на память.</p>
+<p>Картинка кликабельна: <a href="../images/posts/parser-1/1.png" target="_blank"><img src="../images/posts/parser-1/1.png" /></a></p>
<hr />
<div id="sociallinks" class="pull-left">
<strong>Share on:</strong>
View
34 rss.xml
@@ -15,7 +15,11 @@
<id>http://qnikst.github.com/posts/2013-09-06-serialization-p1.html</id>
<published>2013-09-06T00:00:00Z</published>
<updated>2013-09-06T00:00:00Z</updated>
- <summary type="html"><![CDATA[<p><em>У меня тут в черновиках завалялась старый пост про сериализацию стуктур данных в haskell, доводить её до ума и продолжать мне немного лень, но если будет интересно то могу продолжать. Изначально серия статей предполагалась одновременно с доведением до ума пакета <a href="https://github.com/qnikst/strictput">strictput</a></em></p>
+ <summary type="html"><![CDATA[<div style="float:right; width:200px">
+<strong>Updates:</strong><br /> 2013-09-06: исправлены ошибки в тексте (спасибо qrilka)
+</div>
+
+<p><em>У меня тут в черновиках завалялась старый пост про сериализацию стуктур данных в haskell, доводить её до ума и продолжать мне немного лень, но если будет интересно то могу продолжать. Изначально серия статей предполагалась одновременно с доведением до ума пакета <a href="https://github.com/qnikst/strictput">strictput</a></em></p>
<p>Этим постом я хочу начать небольшую серию статей про сериализацию данных в Haskell. и описание библиотек их реализующих.</p>
<h1 id="типы-данных">Типы данных</h1>
<p>Перед тем как рассматривать непосредственно существующие системы сериализации и сопутсвующие им алгоритмы нужно рассмотреть типы данных, в которые можно сериализовать стуктуры. Это позволит упростить описание самой сериализации, а так же улучшит понимание низкого уровня задачи.</p>
@@ -24,9 +28,9 @@
<li>Взаимодействие с внешним рантаймом, например FFI;</li>
<li>Взаимодействие с внешним миром (IPC, передача в сеть и т.д.)</li>
</ol>
-<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором в разных и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам по для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
+<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором — в разных, и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
<h2 id="c-интерфейс">‘C’ интерфейс</h2>
-<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
+<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель, размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
<p>struct iovec { void *iov_base; size_t iov_len; }</p>
<p>в некоторых типах данных можно использовать данный подход, что позволит повысить их производительность, но об этом будет сказано отдельно.</p>
<p>Данный интерфейс может быть изображен в haskell как (# Addr#,CSize #) но крайне не рекомендуется так делать, поскольку это сильно усложнит работу с данными, при этом не принося выгоды, поскольку во многих случаях компилятор может преобразовать структуру к виду аналогичному данному.</p>
@@ -34,10 +38,10 @@
<h3 id="типы-haskell-соотвествующие-c-интерфейсу">Типы haskell соотвествующие C интерфейсу</h3>
<p>В haskell существуют следующие типы соответсующие указателям в C:</p>
<h4 id="addr">Addr#</h4>
-<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
+<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы с этим типом есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
<h4 id="ptr">Ptr</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Ptr</span> a <span class="fu">=</span> <span class="dt">Ptr</span> (<span class="dt">Addr</span><span class="fu">#</span>)</code></pre>
-<p>Типизированная обертка над Addr (lifted, unpacked by default (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
+<p>Типизированная обертка над Addr (lifted, unpacked по умолчанию (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
<p>Функции для работы с указателями предоставляются модулем ‘Foreign.Ptr’</p>
<h4 id="foreignptr">ForeignPtr</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">ForeignPtr</span> <span class="fu">=</span> <span class="dt">ForeignPtr</span> <span class="dt">Addr</span><span class="fu">#</span> <span class="dt">ForeignPtrConents</span></code></pre>
@@ -59,7 +63,7 @@
</ul>
<h3 id="string">String</h3>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">type</span> <span class="dt">String</span> <span class="fu">=</span> [<span class="dt">Char</span>]</code></pre>
-<p>Очень широко используемый тип данных для внутреннего представления тектовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто плохоиспользуется (missused). Поскольку структура данных является ленивой, то возможно создание бесконечных, и цикличеких списков, а так же итеративное построение списка.</p>
+<p>Очень широко используемый тип данных для внутреннего представления текcтовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто используется не по назначению. Поскольку структура данных является ленивой, то возможно создание бесконечных и цикличеких списков, а так же итеративное построение списка.</p>
<p>Характеристики:</p>
<ul>
<li>ленивый</li>
@@ -70,10 +74,10 @@
<li>высокий overhead по памяти для хранения списка (x+8+2)*n+8</li>
<li>очень низкая скорость работы</li>
<li>внутренний (не pinned тип)</li>
-<li>build/foldr deforestation</li>
-<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется не использовать LazyIO, а исполььзовать итеративные библиотеки такие как (pipes, conduit, itertee)</li>
+<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.646">build/foldr deforestation</a></li>
+<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется использовать не ленивый ввод-вывод, а итеративные библиотеки такие как pipes, conduit, или iteratee.</li>
</ul>
-<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это не необходимо, например в случаях если списки играют роль “клея” между операциями.</p>
+<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это без этого можно обойтись, например, в случаях, если списки играют роль “клея” между операциями,.</p>
<p>Операции над структурой данных:</p>
<ul>
<li>size: O(N) /N прыжков по памяти/ const по памяти</li>
@@ -84,7 +88,7 @@
<p>Все операции изменяющие структуру данных пересоздают структуру слева от списка.</p>
<h3 id="word8">[Word8]</h3>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">data</span> [] a <span class="fu">=</span> [] <span class="fu">|</span> a <span class="fu">:</span> [a]</code></pre>
-<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету функционала работы с IO.</p>
+<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету возможностей работы с вводом выводом.</p>
<h3 id="text">Text</h3>
<p>Современный внутренний тип для предствления строковых данных. Однако рассмотрение данного типа выходит за рамки поста.</p>
<h3 id="bytestring">ByteString</h3>
@@ -98,9 +102,9 @@
<p>То, что каждый из блоков данных содержит указатель на начало выделенной памяти позволяет обходиться без дополнительного копирования структуры удаляя её в том случае, если на неё никто не ссылается.</p>
<h3 id="lazy-bytestring">Lazy ByteString</h3>
<p>data ByteString = Empty | Chunk !Internal.ByteString ByteString</p>
-<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие, внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
+<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие: внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
<h2 id="перевод-типов-данных-друг-в-друга">Перевод типов данных друг в друга</h2>
-<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга я привел абсолютно невоспринимаемую картинку: (кто хочет може предложить мне более адекватный вариант).</p>
+<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга, в конце поста я привел абсолютно невоспринимаемую картинку (кто хочет може предложить мне более адекватный вариант).</p>
<p>При переводе типов из одного в другой нужно следить за следующими вещами:</p>
<ol style="list-style-type: decimal">
<li>алгоритмическая сложность операции;</li>
@@ -108,9 +112,9 @@
<li>энергичность/ленивость операции;</li>
<li>безопасность операции.</li>
</ol>
-<p>С первым пунктом все важно, второй тоже важен так как агрессивное использование памяти существенно изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости и не может ли произойти каскадное “форсирование” вычислений в тот момент когда этого допускать нельзя.</p>
-<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её полная копия операции ‘useAs*’ в этом случае нужно понимать, что данный подход приводит к увеличению сложности и нагрузки на память.</p>
-<p><img src="/images/posts/parser-1/1.png"/></p>]]></summary>
+<p>С первым пунктом все важно, второй тоже важен, так как агрессивное использование памяти существенно может изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости, и не может ли произойти каскадное “форсирование” вычислений в тот момент, когда этого допускать нельзя.</p>
+<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры, так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её копия ‘useAs*’. В этом случае нужно понимать, что данный подход приводит к увеличению сложности алгоритма и дополнительной нагрузке на память.</p>
+<p>Картинка кликабельна: <a href="/images/posts/parser-1/1.png" target="_blank"><img src="/images/posts/parser-1/1.png"/></a></p>]]></summary>
</entry>
<entry>
<title>My ghci</title>
View
34 tags/haskell.xml
@@ -15,7 +15,11 @@
<id>http://qnikst.github.com/posts/2013-09-06-serialization-p1.html</id>
<published>2013-09-06T00:00:00Z</published>
<updated>2013-09-06T00:00:00Z</updated>
- <summary type="html"><![CDATA[<p><em>У меня тут в черновиках завалялась старый пост про сериализацию стуктур данных в haskell, доводить её до ума и продолжать мне немного лень, но если будет интересно то могу продолжать. Изначально серия статей предполагалась одновременно с доведением до ума пакета <a href="https://github.com/qnikst/strictput">strictput</a></em></p>
+ <summary type="html"><![CDATA[<div style="float:right; width:200px">
+<strong>Updates:</strong><br /> 2013-09-06: исправлены ошибки в тексте (спасибо qrilka)
+</div>
+
+<p><em>У меня тут в черновиках завалялась старый пост про сериализацию стуктур данных в haskell, доводить её до ума и продолжать мне немного лень, но если будет интересно то могу продолжать. Изначально серия статей предполагалась одновременно с доведением до ума пакета <a href="https://github.com/qnikst/strictput">strictput</a></em></p>
<p>Этим постом я хочу начать небольшую серию статей про сериализацию данных в Haskell. и описание библиотек их реализующих.</p>
<h1 id="типы-данных">Типы данных</h1>
<p>Перед тем как рассматривать непосредственно существующие системы сериализации и сопутсвующие им алгоритмы нужно рассмотреть типы данных, в которые можно сериализовать стуктуры. Это позволит упростить описание самой сериализации, а так же улучшит понимание низкого уровня задачи.</p>
@@ -24,9 +28,9 @@
<li>Взаимодействие с внешним рантаймом, например FFI;</li>
<li>Взаимодействие с внешним миром (IPC, передача в сеть и т.д.)</li>
</ol>
-<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором в разных и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам по для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
+<p>Разница между этими задачами заключается в том, что в первом случае, данные находятся в пространстве одного процесса (группы процессов), а во втором — в разных, и там будет произведено их копирование (существуют варианты, при которых копирование произведено не будет, но их мы оставим в стороне). В связи с этим структуры данных для варинта 1 не должны быть перемещены GC при сборке мусора, поскольку сериализация главным образом интересна нам для второго сценария, то мы не будем посвящать много времени рассмотрению непереносимых (pinned) структур, а будем только отмечать данное свойство.</p>
<h2 id="c-интерфейс">‘C’ интерфейс</h2>
-<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
+<p>При взаимодействии с файлами или сетью для передачи бинарных данных в C принятно использовать пару указатель, размер данных, которая описывает откуда брать данные и сколько. Существуют более интересные варианты для векторной записи (семейство функций read/writev), в этом случае используется массив структур:</p>
<p>struct iovec { void *iov_base; size_t iov_len; }</p>
<p>в некоторых типах данных можно использовать данный подход, что позволит повысить их производительность, но об этом будет сказано отдельно.</p>
<p>Данный интерфейс может быть изображен в haskell как (# Addr#,CSize #) но крайне не рекомендуется так делать, поскольку это сильно усложнит работу с данными, при этом не принося выгоды, поскольку во многих случаях компилятор может преобразовать структуру к виду аналогичному данному.</p>
@@ -34,10 +38,10 @@
<h3 id="типы-haskell-соотвествующие-c-интерфейсу">Типы haskell соотвествующие C интерфейсу</h3>
<p>В haskell существуют следующие типы соответсующие указателям в C:</p>
<h4 id="addr">Addr#</h4>
-<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
+<p>Addr# - unlifted unpacked тип данных являющийся указателем. Стоит напомнить, что данный тип является строгим по построению. С помощью данного типа можно обращаться напрямую к данным внутри примитивных частей программы. Функции для работы с этим типом есть в GHC.Prim (пакет ghc-prim) и Control.Primitive (пакет primitive). Обычно использовние Addr# не нужно, поскольку компилятор умеет приводить приводить работу к данному типу (за это отвечает анализатор строгости).</p>
<h4 id="ptr">Ptr</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Ptr</span> a <span class="fu">=</span> <span class="dt">Ptr</span> (<span class="dt">Addr</span><span class="fu">#</span>)</code></pre>
-<p>Типизированная обертка над Addr (lifted, unpacked by default (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
+<p>Типизированная обертка над Addr (lifted, unpacked по умолчанию (изменится в ghc 7.8)), с помощью данного типа данных можно работать с указателями в “обычном” haskell коде. В подавляющем большинстве случаев ленивость и boxing убираются компилятором. Данный тип не “держит” содержимое на которое указывает и не защищает его от сборки GC.</p>
<p>Функции для работы с указателями предоставляются модулем ‘Foreign.Ptr’</p>
<h4 id="foreignptr">ForeignPtr</h4>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">ForeignPtr</span> <span class="fu">=</span> <span class="dt">ForeignPtr</span> <span class="dt">Addr</span><span class="fu">#</span> <span class="dt">ForeignPtrConents</span></code></pre>
@@ -59,7 +63,7 @@
</ul>
<h3 id="string">String</h3>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">type</span> <span class="dt">String</span> <span class="fu">=</span> [<span class="dt">Char</span>]</code></pre>
-<p>Очень широко используемый тип данных для внутреннего представления тектовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто плохоиспользуется (missused). Поскольку структура данных является ленивой, то возможно создание бесконечных, и цикличеких списков, а так же итеративное построение списка.</p>
+<p>Очень широко используемый тип данных для внутреннего представления текcтовых строк в виде потока (Stream/Lazy-Cons-List). Данный тип предоставляется базовой библиотекой Prelude и поэтому весьма часто используется не по назначению. Поскольку структура данных является ленивой, то возможно создание бесконечных и цикличеких списков, а так же итеративное построение списка.</p>
<p>Характеристики:</p>
<ul>
<li>ленивый</li>
@@ -70,10 +74,10 @@
<li>высокий overhead по памяти для хранения списка (x+8+2)*n+8</li>
<li>очень низкая скорость работы</li>
<li>внутренний (не pinned тип)</li>
-<li>build/foldr deforestation</li>
-<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется не использовать LazyIO, а исполььзовать итеративные библиотеки такие как (pipes, conduit, itertee)</li>
+<li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.646">build/foldr deforestation</a></li>
+<li>IO библиотека существует, но все методы являются ленивыми, что подвергается жесткой критике, рекомендуется использовать не ленивый ввод-вывод, а итеративные библиотеки такие как pipes, conduit, или iteratee.</li>
</ul>
-<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это не необходимо, например в случаях если списки играют роль “клея” между операциями.</p>
+<p>Build/forldr deforestation позволяет не создавать списки в том случае, если это без этого можно обойтись, например, в случаях, если списки играют роль “клея” между операциями,.</p>
<p>Операции над структурой данных:</p>
<ul>
<li>size: O(N) /N прыжков по памяти/ const по памяти</li>
@@ -84,7 +88,7 @@
<p>Все операции изменяющие структуру данных пересоздают структуру слева от списка.</p>
<h3 id="word8">[Word8]</h3>
<pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">data</span> [] a <span class="fu">=</span> [] <span class="fu">|</span> a <span class="fu">:</span> [a]</code></pre>
-<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету функционала работы с IO.</p>
+<p>Аналог String для бинарных типов данных, к данному типу применяемы все пункты относящиеся к String, кроме того, что нету возможностей работы с вводом выводом.</p>
<h3 id="text">Text</h3>
<p>Современный внутренний тип для предствления строковых данных. Однако рассмотрение данного типа выходит за рамки поста.</p>
<h3 id="bytestring">ByteString</h3>
@@ -98,9 +102,9 @@
<p>То, что каждый из блоков данных содержит указатель на начало выделенной памяти позволяет обходиться без дополнительного копирования структуры удаляя её в том случае, если на неё никто не ссылается.</p>
<h3 id="lazy-bytestring">Lazy ByteString</h3>
<p>data ByteString = Empty | Chunk !Internal.ByteString ByteString</p>
-<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие, внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
+<p>Как можно увидеть данная структура изоморфна списку байтстрок, однако есть существенное отличие: внутри каждого чанка существует не произвольная строка, а строка определенного размера. (64k)</p>
<h2 id="перевод-типов-данных-друг-в-друга">Перевод типов данных друг в друга</h2>
-<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга я привел абсолютно невоспринимаемую картинку: (кто хочет може предложить мне более адекватный вариант).</p>
+<p>Для того, чтобы показать как перечисленные типы данных переходят друг в друга, в конце поста я привел абсолютно невоспринимаемую картинку (кто хочет може предложить мне более адекватный вариант).</p>
<p>При переводе типов из одного в другой нужно следить за следующими вещами:</p>
<ol style="list-style-type: decimal">
<li>алгоритмическая сложность операции;</li>
@@ -108,9 +112,9 @@
<li>энергичность/ленивость операции;</li>
<li>безопасность операции.</li>
</ol>
-<p>С первым пунктом все важно, второй тоже важен так как агрессивное использование памяти существенно изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости и не может ли произойти каскадное “форсирование” вычислений в тот момент когда этого допускать нельзя.</p>
-<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её полная копия операции ‘useAs*’ в этом случае нужно понимать, что данный подход приводит к увеличению сложности и нагрузки на память.</p>
-<p><img src="/images/posts/parser-1/1.png"/></p>]]></summary>
+<p>С первым пунктом все важно, второй тоже важен, так как агрессивное использование памяти существенно может изменить поведение программы относительно ожидаемого. То же относится и к ленивости, в этом случае нужно понимать, какие плюсы идут от ленивости, и не может ли произойти каскадное “форсирование” вычислений в тот момент, когда этого допускать нельзя.</p>
+<p>С безопасностью операций дело обстоит интереснее, в том случае если мы передаем выделенную память вне рантайма Haskell, мы не можем гарантировать чистоту данной структуры, так как внешнее окружениме может изменять память как хочет. Обычно для сохранения чистоты в рантайм передается не сама структура, а её копия ‘useAs*’. В этом случае нужно понимать, что данный подход приводит к увеличению сложности алгоритма и дополнительной нагрузке на память.</p>
+<p>Картинка кликабельна: <a href="/images/posts/parser-1/1.png" target="_blank"><img src="/images/posts/parser-1/1.png"/></a></p>]]></summary>
</entry>
<entry>
<title>My ghci</title>

0 comments on commit 4df27ae

Please sign in to comment.
Something went wrong with that request. Please try again.