diff --git a/.gitignore b/.gitignore
index 23c67e5a1..9421b859e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,5 +16,9 @@ output/Scratch/*/*/*/index.html
output/Scratch/*/*/*/*/index.html
output/Scratch/*/*/*/*/*/index.html
output/Scratch/*/*/*/*/*/*/index.html
-output/Scratch/assets/**/*
-crash.log
+output/Scratch/assets/css/*.css
+output/Scratch/*/graph
+output/Scratch/*/*/graph
+output/Scratch/*/*/*/graph
+output/Scratch/*/*/*/*/graph
+output/Scratch/*/*/*/*/*/graph
diff --git a/README.md b/README.md
index 56691d160..0ae48f640 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,8 @@ What you'll need to use it:
- [nanoc](nanoc.stoneship.org) → `gem install nanoc`
- [zsh](zsh.org) → Installed by default on most good system
-- A bunch of gems: `gem install ultraviolet krambook sass rainpress`
+- A bunch of gems: `gem install kramdown builder sass rainpress`
+- Optionally if you want to serve locally: `gem install unicorn rack rack-contrib rack-rewrite mime-types`
Optionally
diff --git a/Rules b/Rules
index 5b871b289..8566eb092 100644
--- a/Rules
+++ b/Rules
@@ -51,14 +51,13 @@ compile '/html/*' do
elsif ext == 'haml' || ext.nil?
filter :haml
elsif ext == 'md' || ext == 'markdown'
- filter :ultraviolet # must be before kramdown
+ filter :code
filter :graph
filter :description
filter :falacy
filter :blogimage
- filter :erb # I'll try not to use ruby anymore inside content
+ filter :erb # I should try to remove all erb code inside markdown
filter :kramdown
- # filter :math_repair # after kramdown
filter :fix_img
else
raise "Filter is not configured for #{item.identifier} in Rules file."
diff --git a/content/css/cmufontface.sass b/content/css/cmufontface.sass
index e7ff54934..c521b7389 100644
--- a/content/css/cmufontface.sass
+++ b/content/css/cmufontface.sass
@@ -1,3 +1,6 @@
+-----
+
+-----
@font-face
font-family: 'cmuntt'
src: url('fonts/cmuntt.eot')
diff --git a/content/css/main2.sass b/content/css/main2.sass
index 334cb2265..f1007dc7d 100644
--- a/content/css/main2.sass
+++ b/content/css/main2.sass
@@ -19,244 +19,224 @@ $blue : #268bd2
$cyan : #2aa198
$green : #859900
-/* $backtext: #FAFAFC */
-$backtext: $base3 + #151515
-$fronttext: $base02
-$hightext: $base03
-$borderColor: $base2
-$altback: $base3
+$unit: 16px
+$lineheight: $unit * 1.5
+$hmargin: 4*$unit
-@import url(/Scratch/assets/css/cmufontface.css)
-
-/* General */
-body
- font-family: 'Futura', serif
- font-size: 20px
- color: $base3
- background: $base02
-
-a, a:link, a:visited, a:active, a:hover
- color: $hightext
- text-decoration: none
- outline: none
-
-a:hover
- color: $orange
-
-hr
- color: $borderColor
- border:
- top: 1px solid $borderColor
- bottom: none
- left: none
- right: none
-
-ul
- list-style: none
- padding-left: 0
- margin-left: 1.5ex
- text-indent: -1.5ex
-ol
- padding-left: 0
-
-ul li:before
- content: "- "
-
-ol li ul, ol li ol, ul li ol, ul li ul
- margin: .5em 1.5em
- list-style: none
-
-/* fix for possible markdown issues */
-li p, ol p
- display: inline
+html
padding: 0
-
-table tr
- &:nth-child(odd)
- background-color: $altback
-table
- border:
- top: solid 2px $borderColor
- bottom: solid 2px $borderColor
-
body
- text-rendering: optimizelegibility
- line-height: 1.5em
-
-h1, h2, h3, h4, h5, h6
- color: $hightext
- line-height: 1.1em
- padding-left: 30px
-
-/* Header Numbering */
-.article #afterheader
- counter-reset: niv02
- h2
- counter-increment: niv02
- counter-reset: niv03
- marker-offset: 3em
- &:before
- content: counter(niv02) ". "
- h3
- counter-increment: niv03
- counter-reset: niv04
- &:before
- content: counter(niv02) "." counter(niv03) ". "
- h4
- counter-increment: niv04
- &:before
- content: counter(niv02) "." counter(niv03) "." counter(niv04) ". "
-
-p, ul, ol, h1, h2, h3, h4
- margin-bottom: 30px
- padding: 0 30px
- text-align: justify
-
-pre
- line-height: 1.1em
- margin-bottom: 30px
- padding: 30px
- overflow: auto
- background: $base3
- font-size: 18px
-
-=sc
- text-transform: uppercase
- font-size: 0.8em
-
-abbr, acronym
- +sc
- text:
- decoration: none
- border:
- bottom:
- width: 0
-
-// -- TYPOGRAPHY --
-.small
- font-size: 0.8em
-
-.sc
- +sc
-
-.clear,.flush
- clear: both
-
-.impact, .darkimpact
- font-size: 2em
- margin: 0 auto 1em auto
- line-height: 1.3em
-
-figure
- margin: 3em 0
- img
- box-shadow: 0 10px 15px #CCC inset
- figcaption
- text-align: center
- margin: .5em 0
-figure.left, figure.right
- max-width: 30%
-
-/* Specific */
-#afterheader
+ padding: 0
+ margin: 0
+body
+ font-family: Helvetica, sans-serif !important
+ font-size: $unit
+ line-height: $lineheight
+ background: $base2
color: $base01
- background-color: $backtext
-.intro, .resume, blockquote
- font-style: italic
- padding: 0.5em 1em
- a:hover
- color: $orange
- i, em
- font-style: normal
- strong, b
- font-weight: normal
-
-.intro, .resume
- font-size: 0.9em
-
-blockquote
- border: solid 1px $borderColor
- background-color: $altback
- pre, pre code
- background-color: $base2
- pre
- border: solid 1px rgba(0,0,0,0.1)
- ul
- padding-left: 1.5em
-
-section.slide
- border-color: $borderColor
- border: solid 1px
- margin-bottom: 1em
- padding: .5em
- font-family: sans-serif
- font-size: .8em
-
-.base03
- color: $base03
-.base02
+a
+ text-decoration: none
color: $base02
-.base01
- color: $base01
-.base00
+a:visited
color: $base00
-.base0
- color: $base0
-.base1
- color: $base1
-.base2
- color: $base2
-.base3
- color: $base3
-.yellow
- color: $yellow
-.orange
- color: $orange
-.red
- color: $red
-.magenta
- color: $magenta
-.violet
- color: $violet
-.blue
- color: $blue
-.cyan
- color: $cyan
-.green
- color: $green
-/* Black page */
-#blackpage
- font-family: sans-serif
- font-style: italic
- padding-top: 8em
- z-index: 9000
- cursor: wait
- img
- background: none
- border: none
- max-width: 80%
- margin: 0 auto
- a
- cursor: pointer
-.cut
- font-size: .8em
- text-align: right
- display: inline-block
+#blackpage, #nojsredirect
+ top: 0
+ left: 0
width: 100%
- opacity: 0.3
+ min-height: 100%
+ margin-left: 0
+ margin-right: 0
+ margin-top: 0
+ margin-bottom: 0
+ position: absolute
+ text-align: center
+ background: $base3
-.cut:hover
- opacity: 1
-
-
-/* Layout */
-#afterheader
- width: 35em
+#content
+ width: 37*$unit + 2*$hmargin
margin: 0 auto
+ padding: 0
+ background: $base3 + #111111
+ color: $base01
+ h1,h2,h3,h4,h5,h6
+ color: $base02
+ padding: 0 $hmargin
+ margin: $unit 0
+ figure
+ margin: 0
+ padding: 0
+ figcaption
+ padding: 0 $hmargin
+ margin: $unit 0
+ p
+ padding: 0 $hmargin
+ margin: $unit 0
img
width: 100%
- img.left, img.right
- width: 30%
+ pre
+ background: $base3
+ font-family: monaco, monospace
+ overflow: auto
+ padding: $unit
+ line-height: $unit + 2px
+ border-top: solid 1px $base2
+ border-bottom: solid 1px $base2
+ pre code
+ background: $base3
+ ul
+ list-style: none
+ ul li:before
+ content: "- "
+ ul
+ padding-left: 0
+ margin: $unit $hmargin
+ // width of '-'
+ text-indent: -($unit/2)
+ ol
+ padding-left: 0
+ margin: $unit $hmargin
+ .toc
+ ol li, ul li
+ margin: ($unit/2) 0
+ ol li ul, ol li ol, ul li ol, ul li ul
+ margin: ($unit/2) (3*$unit/2)
+ list-style: none
+ li p
+ display: inline
+ margin: 0
+ padding: 0
+
+#entete > #choix > #choixrss
+ margin: 0
+ padding: 0
+#entete > #choix > #choixlang
+ float: left
+
+#choix
+ font-size: (3*$unit / 4)
+ padding: 0 $unit
+ .return
+ float: right
+.cut
+ font-size: (3*$unit / 4)
+ opacity: .5
+.cut:hover
+ opacity: 1
+hr
+ color: $base2
+ border-color: $base2
+ margin: 0 ($unit / 4)
+p code, li code
+ padding: 1px 2px
+ background: $base3
+ border: solid 1px $base2
+blockquote
+ border: solid 1px $base2
+ background: $base3
+ code
+ background: $base2
+ border: solid 1px rgba(0,0,0,0.1)
+
+// Specific elements
+#social,#choixrss,#comment
+ margin: $unit $hmargin
+#social
+ float: left
+ opacity: 0.3
+ &:hover
+ opacity: 1
+#choixrss
+ float: right
+ opacity: 0.3
+ &:hover
+ opacity: 1
+#comment
+ img
+ width: auto
+ max-width: 100%
+.intro
+ font-size: 14px
+ line-height: 21px
+ color: $base02
+.left
+ float: left
+.right
+ float: right
+.flush
+ clear: both
+
+#bottom
+ padding: $unit 0
+ background: $base2
+ text-align: center
+ font-size: 14px
+ line-height: 21px
+#entete
+ padding: $unit 0
+ background: $base2
+ text-align: center
+ ul
+ text-indent: 0
+ ul li:before
+ content: ""
+ ul li
+ display: inline-block
+ span.active
+ color: $yellow
+ ul li > *
+ padding: 2px $unit
+ border: solid
+#previous_articles
+ float: left
+ text-align: left
+#next_articles
+ float: right
+ text-align: right
+.corps
+ padding-bottom: 2*$unit
+
+#tagcloud
+ margin: $unit $hmargin
+ font-size: 14px
+ line-height: 21px
+#sousliens.archive > ul
+ display: none
+#sousliens.archive > h4:hover
+ cursor: pointer
+#hiddenDivs > div
+ display: none
+.list
+ margin: $unit $hmargin
+#content img#mainlogo
+ width: auto
+ margin: 0 auto
+ display: block
+ max-width: 100%
+.date, .day, .month, .year
+ display: inline-block
+ padding-left: 10px
+ text-align: right
+.day
+ width: 10px
+.month
+ width: 20px
+.year
+ width: 30px
+.date
+ margin-right: 10px
+
+.popularblock
+ display: block
+ float: left
+ margin: 1.5%
+ width: 30%
+ figure
+ width: 100%
+ height: 120px
+ overflow: hidden
+ figcaption
+ display: none
+
diff --git a/lib/graph.mp b/lib/graph.mp
new file mode 100644
index 000000000..117b36ccc
--- /dev/null
+++ b/lib/graph.mp
@@ -0,0 +1,196 @@
+% solarized color scheme
+color baseZeroThree, baseZeroTwo, baseZeroOne, baseZeroZero
+ , baseZero, baseOne, baseTwo, baseThree, yellow, orange
+ , red, magenta, violet, blue, cyan, green;
+baseZeroThree :=(0.0 ,0.168627450980392,0.211764705882353);
+baseZeroTwo :=(0.0274509803921569,0.211764705882353,0.258823529411765);
+baseZeroOne :=(0.345098039215686 ,0.431372549019608,0.458823529411765);
+baseZeroZero :=(0.396078431372549 ,0.482352941176471,0.513725490196078);
+baseZero :=(0.513725490196078 ,0.580392156862745,0.588235294117647);
+baseOne :=(0.576470588235294 ,0.631372549019608,0.631372549019608);
+baseTwo :=(0.933333333333333 ,0.909803921568627,0.835294117647059);
+baseThree :=(0.992156862745098 ,0.964705882352941,0.890196078431372);
+yellow :=(0.709803921568627 ,0.537254901960784,0.0);
+orange :=(0.796078431372549 ,0.294117647058824,0.0862745098039216);
+red :=(0.862745098039216 ,0.196078431372549,0.184313725490196);
+magenta :=(0.827450980392157 ,0.211764705882353,0.509803921568627);
+violet :=(0.423529411764706 ,0.443137254901961,0.768627450980392);
+blue :=(0.149019607843137 ,0.545098039215686,0.823529411764706);
+cyan :=(0.164705882352941 ,0.631372549019608,0.596078431372549);
+green :=(0.52156862745098 ,0.6 ,0.0);
+
+
+vardef shorten(expr p,d) =
+ path q,bcirc,ecirc;
+ bcirc := fullcircle scaled d shifted point 0 of p;
+ ecirc := fullcircle scaled d shifted point length(p) of p;
+ q := p cutbefore bcirc cutafter ecirc;
+ q
+enddef;
+
+%%%%%%%%%%%%%%%%%%%%
+% Automata drawing %
+%%%%%%%%%%%%%%%%%%%%
+u:=.5cm; % unity
+gu:=5u; % distance between states
+
+% -- Generic private functions
+
+% return the edge between points A and B.
+% out angle from A is inan
+% in angle to B is outan
+% nodesize is the size of the node
+vardef _edgeFullParam(expr posA,posB,inan,outan,nodesize) =
+ path sub;
+ if (posA = posB):
+ pair ba,ea,b;
+ path circ,p;
+ b :=posA shifted (0,nodesize);
+ p:=posA{1,1}..b..{1,-1}cycle;
+ circ:= fullcircle scaled nodesize shifted posA;
+ ba = circ intersectionpoint (subpath (0,1) of p);
+ ea = circ intersectionpoint (subpath (1,2) of p);
+ sub:= ba{1,1}..b..{1,-1}ea;
+ else:
+ path s; s := posA {dir inan} .. {dir outan} posB ;
+ pair bA;
+ pair bA; bA = (fullcircle scaled nodesize shifted posA) intersectionpoint s;
+ pair eB; eB = (fullcircle scaled nodesize shifted posB) intersectionpoint s;
+ sub := bA {dir inan} .. {dir outan} eB ;
+ fi
+ sub
+enddef;
+
+% return a picture of the label l for edge e
+vardef _edgelabel(expr e,l) =
+ picture ret;
+ pair mid;
+ mid := point 1/2length(e) of e;
+ numeric an;
+ an := angle (direction 1/2length(e) of e);
+ picture lab;
+ pair height,width;
+ lab:=thelabel(l,origin);
+ height:=(0,ypart (ulcorner l - llcorner l));
+ width:=(ypart (urcorner l - ulcorner l),0);
+ if (an>-35) and (an<35):
+ ret:=lab shifted height rotated an shifted mid;
+ elseif (an>145) or (an<-145):
+ ret:=thelabel(l,origin) shifted height rotated (an+180) shifted mid;
+ elseif (an>75) and (an<120):
+ ret:=lab shifted mid shifted -width;
+ elseif (an>-120) and (an<-75):
+ ret:=lab shifted mid shifted width;
+ else:
+ ret:=lab shifted mid shifted height;
+ fi;
+ ret
+enddef;
+
+% draw an edge
+def _drawEdgeFullParam(expr posA,posB,l,inan,outan,nodesize) =
+ path sub;
+ picture lab;
+ sub := _edgeFullParam(posA,posB,inan,outan,nodesize);
+ drawarrow sub;
+ draw _edgelabel(sub,l);
+enddef;
+
+
+% --- LABELED GRAPHS ---
+% return the edge between points A and B.
+% out angle from A is inan
+vardef edgeAngle(expr posA,posB,an) =
+ path sub;
+ sub := _edgeFullParam(posA,posB,an,-an,1.2u);
+ sub
+enddef;
+% return the direct edge between A and B
+vardef edge(expr posA,posB) =
+ numeric an;
+ an := angle(posB-posA);
+ path sub;
+ sub := _edgeFullParam(posA,posB,an,an,1.2u);
+ sub
+enddef;
+
+% --- UNLABELED GRAPHS ---
+% return the edge between points A and B.
+% out angle from A is inan
+vardef nl_edgeAngle(expr posA,posB,an) =
+ path sub;
+ sub := _edgeFullParam(posA,posB,an,-an,6);
+ sub
+enddef;
+% return the direct edge between A and B
+vardef nl_edge(expr posA,posB) =
+ numeric an;
+ an := angle(posB-posA);
+ path sub;
+ sub := _edgeFullParam(posA,posB,an,an,6);
+ sub
+enddef;
+
+def drawloop(expr a,b,l) =
+ pair ba,ea;
+ path circ,p,s;
+ p:=a{1,1}..b..{1,-1}cycle;
+ circ:= fullcircle scaled 6 shifted a;
+ ba = circ intersectionpoint (subpath (0,1) of p);
+ ea = circ intersectionpoint (subpath (1,2) of p);
+ s:= ba{1,1}..b..{1,-1}ea;
+ drawarrow s;
+ label.top(l,b);
+enddef;
+
+def drawLoop(expr a,l) =
+ pair b; b:=a shifted (0,u);
+ pair ba,ea;
+ path circ,p,s;
+ p:=a{1,1}..b..{1,-1}cycle;
+ circ:= fullcircle scaled 1.2u shifted a;
+ ba = circ intersectionpoint (subpath (0,1) of p);
+ ea = circ intersectionpoint (subpath (1,2) of p);
+ s:= ba{1,1}..b..{1,-1}ea;
+ drawarrow s;
+ label.top(l,b);
+enddef;
+def drawstate(expr pos) =
+ draw pos withpen pencircle scaled 4bp;
+enddef;
+def drawedgeWithDoubleAngle(expr posA,posB,l,inan,outan) =
+ _drawEdgeFullParam(posA,posB,l,inan,outan,6);
+enddef;
+
+def drawedgeangle(expr posA,posB,l,an) =
+ _drawEdgeFullParam(posA,posB,l,an,-an,6);
+enddef;
+def drawedge(expr posA,posB,l) =
+ numeric an;
+ an=angle(posB-posA);
+ _drawEdgeFullParam(posA,posB,l,an,an,6);
+enddef;
+
+def drawState(expr pos,l) =
+ label(l,pos);
+ draw fullcircle scaled u shifted pos;
+enddef;
+
+def drawEdgeWithDoubleAngle(expr posA,posB,l,inan,outan) =
+ _drawEdgeFullParam(posA,posB,l,inan,outan,1.2u);
+enddef;
+def drawEdgeWithAngle(expr posA,posB,l,an) =
+ drawEdgeWithDoubleAngle(posA,posB,l,an,-an);
+enddef;
+def drawEdge(expr posA,posB,l) =
+ numeric an;
+ if (posA = posB):
+ an := 0;
+ else:
+ an=angle(posB-posA);
+ fi
+ drawEdgeWithDoubleAngle(posA,posB,l,an,an);
+enddef;
+
+prologues:=3;
+
diff --git a/lib/graph.rb b/lib/graph.rb
index 2ee5284e5..09a41412b 100644
--- a/lib/graph.rb
+++ b/lib/graph.rb
@@ -1,6 +1,41 @@
class Graph < Nanoc3::Filter
identifier :graph
@@tmpfic="/tmp/graphtemp.dot"
+ def solarized(str)
+ str.gsub(
+ %r{color="base03"},'color="#002b36"'
+ ).gsub(
+ %r{color="base02"},'color="#073642"'
+ ).gsub(
+ %r{color="base01"},'color="#586e75"'
+ ).gsub(
+ %r{color="base00"},'color="#657b83"'
+ ).gsub(
+ %r{color="base0"},'color="#839496"'
+ ).gsub(
+ %r{color="base1"},'color="#93a1a1"'
+ ).gsub(
+ %r{color="base2"},'color="#eee8d5"'
+ ).gsub(
+ %r{color="base3"},'color="#fdf6e3"'
+ ).gsub(
+ %r{color="yellow"},'color="#b58900"'
+ ).gsub(
+ %r{color="orange"},'color="#cb4b16"'
+ ).gsub(
+ %r{color="red"},'color="#dc322f"'
+ ).gsub(
+ %r{color="magenta"},'color="#d33682"'
+ ).gsub(
+ %r{color="violet"},'color="#6c71c4"'
+ ).gsub(
+ %r{color="blue"},'color="#268bd2"'
+ ).gsub(
+ %r{color="cyan"},'color="#2aa198"'
+ ).gsub(
+ %r{color="green"},'color="#859900"'
+ )
+ end
def run(content, params={})
content.gsub(%r{
And you can see the intermediate steps to reach this goal:
- +From the 2nd section to the 4th it will be dirtier and dirtier. We start cleaning the code at the 5th section.
@@ -152,7 +152,7 @@ We start cleaning the code at the 5th section. The first being mostly some boilerplate2. And the second part more focused on OpenGL and content. -Well, if you download this file (look at the bottom of this section), compile it and run it this is the result:
- +A first very interesting property of this program is that the computation for all the points is done only once.
It is a bit long before the first image appears, but if you resize the window, it updates instantaneously.
This property is a direct consequence of purity.
If you look closely, you see that allPoints
is a pure list.
Therefore, calling allPoints
will always render the same result and Haskell is clever enough to use this property.
-While Haskell doesn’t garbage collect allPoints
the result is reused for free.
+While Haskell doesn’t garbage collect allPoints
the result is reused for free.
We did not specified this value should be saved for later use.
It is saved for us.
See what occurs if we make the window bigger:
- +We see some black lines because we have drawn less point than there is on the surface. We can repair this by drawing little squares instead of just points. @@ -565,7 +565,7 @@ maxZeroIndex func minval maxval n =
No rocket science here. See the result now:
- + -This code is cleaner but many things doesn’t feel right. +
This code is cleaner but many things doesn’t feel right. First, all the user interaction code is outside our main file. I feel it is okay to hide the detail for the rendering. But I would have preferred to control the user actions.
@@ -1271,12 +1271,12 @@ We will have two choices:Our main problem come from user interaction. -If you ask “the Internet”, +If you ask “the Internet”, about how to deal with user interaction with a functional paradigm, the main answer is to use functional reactive programming (FRP). -I won’t use FRP in this article. -Instead, I’ll use a simpler while less effective way to deal with user interaction. -But The method I’ll use will be as pure and functional as possible.
+I won’t use FRP in this article. +Instead, I’ll use a simpler while less effective way to deal with user interaction. +But The method I’ll use will be as pure and functional as possible.Here is a real working code, I’ve hidden most display functions. +
Here is a real working code, I’ve hidden most display functions. The YGL, is a kind of framework to display 3D functions. But it can easily be extended to many kind of representation.
@@ -1518,7 +1518,7 @@ idleAction tnew world = world {Now the function which will generate points in 3D.
The first parameter (res
) is the resolution of the vertex generation.
More precisely, res
is distance between two points on one direction.
-We need it to “close” our shape.
The type Function3D
is Point -> Point -> Maybe Point
.
Because we consider partial functions
@@ -1587,7 +1587,7 @@ ymandel x y z = fromIntegral (mandel x y z 64) / 64
I won’t explain how the magic occurs here. +
I won’t explain how the magic occurs here.
If you are interested, just read the file YGL.hs
.
It is commented a lot.
Our code architecture feel very clean.
All the meaningful code is in our main file and all display details are
externalized.
-If you read the code of YGL.hs
, you’ll see I didn’t made everything perfect.
-For example, I didn’t finished the code of the lights.
+If you read the code of YGL.hs
, you’ll see I didn’t made everything perfect.
+For example, I didn’t finished the code of the lights.
But I believe it is a good first step and it will be easy to go further.
Unfortunately the program of the preceding session is extremely slow.
We compute the Mandelbulb for each frame now.
As we can use imperative style in a functional language, know you can use functional style in imperative languages. This article exposed a way to organize some code in a functional way. -I’d like to stress the usage of Haskell made it very simple to achieve this.
+I’d like to stress the usage of Haskell made it very simple to achieve this.Once you are used to pure functional style, it is hard not to see all advantages it offers.
The code in the two last sections is completely pure and functional.
-Furthermore I don’t use GLfloat
, Color3
or any other OpenGL type.
+Furthermore I don’t use GLfloat
, Color3
or any other OpenGL type.
If I want to use another library in the future,
I would be able to keep all the pure code and simply update the YGL module.
The YGL
module can be seen as a “wrapper” around 3D display and user interaction.
+
The YGL
module can be seen as a “wrapper” around 3D display and user interaction.
It is a clean separator between the imperative paradigm and functional paradigm.
If you want to go further, it shouldn’t be hard to add parallelism. +
If you want to go further, it shouldn’t be hard to add parallelism. This should be easy mainly because most of the visible code is pure. Such an optimization would have been harder by using directly the OpenGL library.
@@ -1915,7 +1915,7 @@ O(n².log(n)) to O(n³).Unfortunately, I couldn’t make this program to work on my Mac. More precisely, I couldn’t make the DevIL library work on Mac to output the image. Yes I have done a brew install libdevil
. But even a minimal program who simply write some jpg
didn’t worked. I tried both with Haskell
and C
.↩
Unfortunately, I couldn’t make this program to work on my Mac. More precisely, I couldn’t make the DevIL library work on Mac to output the image. Yes I have done a brew install libdevil
. But even a minimal program who simply write some jpg
didn’t worked. I tried both with Haskell
and C
.↩
Generally in Haskell you need to declare a lot of import lines. @@ -2010,10 +2010,14 @@ O(n².log(n)) to O(n³).
next entries + +tlàl : Un exemple progressif d’utilisation d’Haskell. +
tlàl : Un exemple progressif d’utilisation d’Haskell. Vous pourrez voir un ensemble de Mandelbrot étendu à la troisième dimension. De plus le code sera très propre. Les détails de rendu sont séparés dans un module externe. @@ -67,7 +67,7 @@ Vous pouvez vous inspirer de ce code utilisant le paradigme fonctional dans tous
And you can see the intermediate steps to reach this goal:
- +From the 2nd section to the 4th it will be dirtier and dirtier. We start cleaning the code at the 5th section.
@@ -152,7 +152,7 @@ We start cleaning the code at the 5th section. The first being mostly some boilerplate2. And the second part more focused on OpenGL and content. -Well, if you download this file (look at the bottom of this section), compile it and run it this is the result:
- +A first very interesting property of this program is that the computation for all the points is done only once.
It is a bit long before the first image appears, but if you resize the window, it updates instantaneously.
This property is a direct consequence of purity.
If you look closely, you see that allPoints
is a pure list.
Therefore, calling allPoints
will always render the same result and Haskell is clever enough to use this property.
-While Haskell doesn’t garbage collect allPoints
the result is reused for free.
+While Haskell doesn’t garbage collect allPoints
the result is reused for free.
We did not specified this value should be saved for later use.
It is saved for us.
See what occurs if we make the window bigger:
- +We see some black lines because we have drawn less point than there is on the surface. We can repair this by drawing little squares instead of just points. @@ -565,7 +565,7 @@ maxZeroIndex func minval maxval n =
No rocket science here. See the result now:
- + -This code is cleaner but many things doesn’t feel right. +
This code is cleaner but many things doesn’t feel right. First, all the user interaction code is outside our main file. I feel it is okay to hide the detail for the rendering. But I would have preferred to control the user actions.
@@ -1271,12 +1271,12 @@ We will have two choices:Our main problem come from user interaction. -If you ask “the Internet”, +If you ask “the Internet”, about how to deal with user interaction with a functional paradigm, the main answer is to use functional reactive programming (FRP). -I won’t use FRP in this article. -Instead, I’ll use a simpler while less effective way to deal with user interaction. -But The method I’ll use will be as pure and functional as possible.
+I won’t use FRP in this article. +Instead, I’ll use a simpler while less effective way to deal with user interaction. +But The method I’ll use will be as pure and functional as possible.Here is a real working code, I’ve hidden most display functions. +
Here is a real working code, I’ve hidden most display functions. The YGL, is a kind of framework to display 3D functions. But it can easily be extended to many kind of representation.
@@ -1518,7 +1518,7 @@ idleAction tnew world = world {Now the function which will generate points in 3D.
The first parameter (res
) is the resolution of the vertex generation.
More precisely, res
is distance between two points on one direction.
-We need it to “close” our shape.
The type Function3D
is Point -> Point -> Maybe Point
.
Because we consider partial functions
@@ -1587,7 +1587,7 @@ ymandel x y z = fromIntegral (mandel x y z 64) / 64
I won’t explain how the magic occurs here. +
I won’t explain how the magic occurs here.
If you are interested, just read the file YGL.hs
.
It is commented a lot.
Our code architecture feel very clean.
All the meaningful code is in our main file and all display details are
externalized.
-If you read the code of YGL.hs
, you’ll see I didn’t made everything perfect.
-For example, I didn’t finished the code of the lights.
+If you read the code of YGL.hs
, you’ll see I didn’t made everything perfect.
+For example, I didn’t finished the code of the lights.
But I believe it is a good first step and it will be easy to go further.
Unfortunately the program of the preceding session is extremely slow.
We compute the Mandelbulb for each frame now.
As we can use imperative style in a functional language, know you can use functional style in imperative languages. This article exposed a way to organize some code in a functional way. -I’d like to stress the usage of Haskell made it very simple to achieve this.
+I’d like to stress the usage of Haskell made it very simple to achieve this.Once you are used to pure functional style, it is hard not to see all advantages it offers.
The code in the two last sections is completely pure and functional.
-Furthermore I don’t use GLfloat
, Color3
or any other OpenGL type.
+Furthermore I don’t use GLfloat
, Color3
or any other OpenGL type.
If I want to use another library in the future,
I would be able to keep all the pure code and simply update the YGL module.
The YGL
module can be seen as a “wrapper” around 3D display and user interaction.
+
The YGL
module can be seen as a “wrapper” around 3D display and user interaction.
It is a clean separator between the imperative paradigm and functional paradigm.
If you want to go further, it shouldn’t be hard to add parallelism. +
If you want to go further, it shouldn’t be hard to add parallelism. This should be easy mainly because most of the visible code is pure. Such an optimization would have been harder by using directly the OpenGL library.
@@ -1915,7 +1915,7 @@ O(n².log(n)) to O(n³).Unfortunately, I couldn’t make this program to work on my Mac. More precisely, I couldn’t make the DevIL library work on Mac to output the image. Yes I have done a brew install libdevil
. But even a minimal program who simply write some jpg
didn’t worked. I tried both with Haskell
and C
.↩
Unfortunately, I couldn’t make this program to work on my Mac. More precisely, I couldn’t make the DevIL library work on Mac to output the image. Yes I have done a brew install libdevil
. But even a minimal program who simply write some jpg
didn’t worked. I tried both with Haskell
and C
.↩
Generally in Haskell you need to declare a lot of import lines. @@ -2010,10 +2010,14 @@ O(n².log(n)) to O(n³).
articles suivants + +