scratch/output/Scratch/fr/blog/Higher-order-function-in-zsh/index.html
Yann Esposito (Yogsototh) 219937b6c9 Regen
2012-01-18 14:28:01 +01:00

342 lines
No EOL
19 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.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="keywords" content="zsh, map, foldr, filter, functional, programming, higher order functions">
<link rel="shortcut icon" type="image/x-icon" href="/Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/Scratch/assets/css/main.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/twilight.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/idc.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://feeds.feedburner.com/yannespositocomfr"/>
<link rel="alternate" lang="fr" xml:lang="fr" title="Fonctions d'ordre supérieur en zsh" type="text/html" hreflang="fr" href="/Scratch/fr/blog/Higher-order-function-in-zsh/" />
<link rel="alternate" lang="en" xml:lang="en" title="Higher order function in zsh" type="text/html" hreflang="en" href="/Scratch/en/blog/Higher-order-function-in-zsh/" />
<script type="text/javascript" src="/Scratch/js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="/Scratch/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/Scratch/js/index.js"></script>
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<title>Fonctions d'ordre supérieur en zsh</title>
</head>
<body lang="fr" class="article">
<script type="text/javascript">// <![CDATA[
document.write('<div id="blackpage"><img src="/Scratch/img/loading.gif" alt="Chargement en cours..."/></div>');
// ]]>
</script>
<div id="content">
<div id="choix">
<div class="return"><a href="#entete">&darr; Menu &darr;</a></div>
<div id="choixlang">
<a href="/Scratch/en/blog/Higher-order-function-in-zsh/" onclick="setLanguage('en')">in English</a>
</div>
<div class="flush"></div>
</div>
<div id="titre">
<h1>
Fonctions d'ordre supérieur en zsh
</h1>
</div>
<div class="flush"></div>
<div class="flush"></div>
<div id="afterheader">
<div class="corps">
<p><img alt="Title image" src="/Scratch/img/blog/Higher-order-function-in-zsh/main.jpg" /></p>
<div class="intro">
<p><span class="sc"><abbr title="Trop long à lire">tlàl</abbr>&nbsp;: </span> des fonctions dordres supérieurs en zsh.</p>
</div>
<p>Tout dabord, pourquoi cest important davoir ces fonctions.
Plus je programmais avec zsh plus jessayais davoir un style fonctionnel.</p>
<p>Le minimum pour pouvoir avoir du code plus lisible cest de posséder les fonctions <code>map</code>, <code>filter</code> et <code>fold</code>.</p>
<p>Voici pourquoi avec une comparaison.
Commençons par un programme qui converti tous les gif en png dans plusieurs répertoires projets contenant tous des répertoires resources.
Avant&nbsp;:</p>
<p>Avant ⇒</p>
<pre class="twilight">
<span class="Comment"><span class="Comment">#</span> for each directory in projects dir</span>
<span class="Keyword">for</span> toProject <span class="Keyword">in</span> /path/to/projects/*(/N)<span class="Keyword">;</span> <span class="Keyword">do</span>
<span class="Comment"><span class="Comment">#</span> toProject is /path/to/projects/foo</span>
<span class="Comment"><span class="Comment">#</span> project become foo (:t for tail)</span>
project=<span class="Variable"><span class="Variable">${</span>toProject:t<span class="Variable">}</span></span>
<span class="Keyword">for</span> toResource <span class="Keyword">in</span> <span class="Variable"><span class="Variable">$</span>toProject</span>/resources/*.gif(.N)<span class="Keyword">;</span> <span class="Keyword">do</span>
convert <span class="Variable"><span class="Variable">$</span>toResource</span> <span class="Variable"><span class="Variable">${</span>toResource:r<span class="Variable">}</span></span>.png <span class="Keyword">&amp;&amp;</span> \
<span class="Constant">\r</span>m -f <span class="Variable"><span class="Variable">$</span>toResource</span>
<span class="Keyword">done</span>
<span class="Keyword">done</span>
</pre>
<ul>
<li>Le <code>(/N)</code> permet de sélectionner seulement les répertoires sans casser la boucle sil ny a pas de “match”.</li>
<li>Le <code>(.N)</code> permet de sélection seulement les fichiers, aussi sans tout arréter sil ne trouve rien.</li>
<li>Le <code>:t</code> signfie “tail”&nbsp;; si <code>toto=/path/to/file.ext</code> alors <code>${toto:t}=file.ext</code>.</li>
</ul>
<p>Après</p>
<pre class="twilight">
<span class="Entity">gif_to_png</span>() { convert <span class="Variable"><span class="Variable">$</span>1</span> <span class="Variable"><span class="Variable">${</span>1:r<span class="Variable">}</span></span>.png <span class="Keyword">&amp;&amp;</span> <span class="Constant">\r</span>m -f <span class="Variable"><span class="Variable">$</span>1</span> }
<span class="Entity">handle_resources</span>() { map gif_to_png <span class="Variable"><span class="Variable">$</span>1</span>/resources/*.gif(.N) }
map handle_resources /path/to/projects/*(/N)
</pre>
<p>Plus de bloc&nbsp;!
Oui, cest un poil plus difficile à lire pour les non initiés.
Mais cest à la fois plus concis et plus robuste.</p>
<p>Et encore ce code ne possède pas de test.
Recommençons sur le même principe.</p>
<p>Trouver les fichiers des projets qui ne contiennent pas de s dans leur nom qui ont le même nom que leur projet.</p>
<p>Before ⇒</p>
<pre class="twilight">
<span class="Keyword">for</span> toProject <span class="Keyword">in</span> Projects/*<span class="Keyword">;</span> <span class="Keyword">do</span>
project=<span class="Variable"><span class="Variable">$</span>toProject</span>:t
<span class="Keyword">if</span> print -- project <span class="Keyword">|</span> grep -v s <span class="Keyword">&gt;</span>/dev/null
<span class="Keyword">then</span>
print <span class="Variable"><span class="Variable">$</span>project</span>
<span class="Keyword">for</span> toResource <span class="Keyword">in</span> <span class="Variable"><span class="Variable">$</span>toProject</span>/*(.N)<span class="Keyword">;</span> <span class="Keyword">do</span>
<span class="Keyword">if</span> print -- <span class="Variable"><span class="Variable">${</span>toResource:t<span class="Variable">}</span></span> <span class="Keyword">|</span> grep <span class="Variable"><span class="Variable">$</span>project</span> <span class="Keyword">&gt;</span>/dev/null<span class="Keyword">;</span> <span class="Keyword">then</span>
print -- <span class="String"><span class="String">&quot;</span>X <span class="StringVariable"><span class="StringVariable">$</span>toResource</span><span class="String">&quot;</span></span>
<span class="Keyword">fi</span>
<span class="Keyword">done</span>
<span class="Keyword">fi</span>
<span class="Keyword">done</span>
</pre>
<p>After ⇒</p>
<pre class="twilight">
<span class="Entity">contain_no_s</span>() { print <span class="Variable"><span class="Variable">$</span>1</span> <span class="Keyword">|</span> grep -v s }
function verify_file_name {
local project=<span class="Variable"><span class="Variable">$</span>1</span>:t
<span class="Entity">contains_project_name</span>() { print <span class="Variable"><span class="Variable">$</span>1</span>:t <span class="Keyword">|</span> grep <span class="Variable"><span class="Variable">$</span>project</span> }
map <span class="String"><span class="String">&quot;</span>print -- X<span class="String">&quot;</span></span> <span class="String"><span class="String">$(</span>filter contains_project_name <span class="StringVariable"><span class="StringVariable">$</span>1</span>/*<span class="String"><span class="String">(</span>.N<span class="String">)</span></span><span class="String">)</span></span>
}
map verify_file_name <span class="String"><span class="String">$(</span> filter contain_no_s Projects/* <span class="String">)</span></span>
</pre>
<p>La première version peu paraître plus facile à lire.
Mais la seconde est plus bien supérieure en terme darchitecture.
Je ne veux pas discuster ici pourquoi cest mieux.
Je vous demande simplement de me croire quand je dis que lapproche fonctionnelle est supérieure.</p>
<p>Actuellement il me manque une fonction lambda, si quelquun à une idée elle serait la bienvenue.
Je ne sais pas encore comment créer facilement des fonctions anonymes.</p>
<p>Voici le code source&nbsp;:</p>
<div class="code"><div class="file"><a href="/Scratch/fr/blog/Higher-order-function-in-zsh/code/functional.sh"> &#x27A5; functional.sh </a></div><div class="withfile">
<pre class="twilight">
<span class="Comment"><span class="Comment">#</span>!/usr/bin/env zsh</span>
<span class="Comment"><span class="Comment">#</span> Provide higer-order functions </span>
<span class="Comment"><span class="Comment">#</span> usage:</span>
<span class="Comment"><span class="Comment">#</span></span>
<span class="Comment"><span class="Comment">#</span> $ foo(){print &quot;x: $1&quot;}</span>
<span class="Comment"><span class="Comment">#</span> $ map foo a b c d</span>
<span class="Comment"><span class="Comment">#</span> x: a</span>
<span class="Comment"><span class="Comment">#</span> x: b</span>
<span class="Comment"><span class="Comment">#</span> x: c</span>
<span class="Comment"><span class="Comment">#</span> x: d</span>
function map {
local func_name=<span class="Variable"><span class="Variable">$</span>1</span>
shift
<span class="Keyword">for</span> elem <span class="Keyword">in</span> <span class="Variable"><span class="Variable">$</span>@</span><span class="Keyword">;</span> print -- <span class="String"><span class="String">$(</span>eval <span class="StringVariable"><span class="StringVariable">$</span>func_name</span> <span class="StringVariable"><span class="StringVariable">$</span>elem</span><span class="String">)</span></span>
}
<span class="Comment"><span class="Comment">#</span> $ bar() { print $(($1 + $2)) }</span>
<span class="Comment"><span class="Comment">#</span> $ fold bar 0 1 2 3 4 5</span>
<span class="Comment"><span class="Comment">#</span> 15</span>
<span class="Comment"><span class="Comment">#</span> -- but also</span>
<span class="Comment"><span class="Comment">#</span> $ fold bar 0 $( seq 1 100 )</span>
function fold {
<span class="Keyword">if</span> ((<span class="Variable"><span class="Variable">$</span>#</span><span class="Keyword">&lt;</span>2)) {
print -- <span class="String"><span class="String">&quot;</span>ERROR fold use at least 2 arguments<span class="String">&quot;</span></span> <span class="Keyword">&gt;&amp;2</span>
return 1
}
<span class="Keyword">if</span> ((<span class="Variable"><span class="Variable">$</span>#</span><span class="Keyword">&lt;</span>3)) {
print -- <span class="Variable"><span class="Variable">$</span>2</span>
return 0
} <span class="Keyword">else</span> {
local acc
local right
local func_name=<span class="Variable"><span class="Variable">$</span>1</span>
local init_value=<span class="Variable"><span class="Variable">$</span>2</span>
local first_value=<span class="Variable"><span class="Variable">$</span>3</span>
shift 3
right=<span class="String"><span class="String">$(</span> fold <span class="StringVariable"><span class="StringVariable">$</span>func_name</span> <span class="StringVariable"><span class="StringVariable">$</span>init_value</span> <span class="StringVariable"><span class="StringVariable">$</span>@</span> <span class="String">)</span></span>
acc=<span class="String"><span class="String">$(</span> eval <span class="String"><span class="String">&quot;</span><span class="StringVariable"><span class="StringVariable">$</span>func_name</span> <span class="StringVariable"><span class="StringVariable">$</span>first_value</span> <span class="StringVariable"><span class="StringVariable">$</span>right</span><span class="String">&quot;</span></span> <span class="String">)</span></span>
print -- <span class="Variable"><span class="Variable">$</span>acc</span>
return 0
}
}
<span class="Comment"><span class="Comment">#</span> usage:</span>
<span class="Comment"><span class="Comment">#</span></span>
<span class="Comment"><span class="Comment">#</span> $ baz() { print $1 | grep baz }</span>
<span class="Comment"><span class="Comment">#</span> $ filter baz titi bazaar biz</span>
<span class="Comment"><span class="Comment">#</span> bazaar</span>
function filter {
local predicate=<span class="Variable"><span class="Variable">$</span>1</span>
local result
typeset -a result
shift
<span class="Keyword">for</span> elem <span class="Keyword">in</span> <span class="Variable"><span class="Variable">$</span>@</span><span class="Keyword">;</span> <span class="Keyword">do</span>
<span class="Keyword">if</span> eval <span class="Variable"><span class="Variable">$</span>predicate</span> <span class="Variable"><span class="Variable">$</span>elem</span> <span class="Keyword">&gt;</span>/dev/null<span class="Keyword">;</span> <span class="Keyword">then</span>
result=( <span class="Variable"><span class="Variable">$</span>result</span> <span class="Variable"><span class="Variable">$</span>elem</span> )
<span class="Keyword">fi</span>
<span class="Keyword">done</span>
print <span class="Variable"><span class="Variable">$</span>result</span>
}
</pre>
</div></div>
</div>
<div id="choixrss">
<a id="rss" href="http://feeds.feedburner.com/yannespositocomfr">
s'abonner
</a>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#comment').hide();
$('#clickcomment').click(showComments);
});
function showComments() {
$('#comment').show();
$('#clickcomment').fadeOut();
}
document.write('<div id="clickcomment">Commentaires</div>');
</script>
<div class="flush"></div>
<div class="corps" id="comment">
<h2 class="first">commentaires</h2>
<noscript>
Vous devez activer javascript pour commenter.
</noscript>
<script type="text/javascript">
var idcomments_acct = 'a307f0044511ff1b5cfca573fc0a52e7';
var idcomments_post_id = '/Scratch/fr/blog/Higher-order-function-in-zsh/';
var idcomments_post_url = 'http://yannesposito.com/Scratch/fr/blog/Higher-order-function-in-zsh/';
</script>
<span id="IDCommentsPostTitle" style="display:none"></span>
<script type='text/javascript' src='/Scratch/js/genericCommentWrapperV2.js'></script>
</div>
<div id="entete" class="corps_spaced">
<div id="liens">
<ul><li><a href="/Scratch/fr/">Bienvenue</a></li>
<li><a href="/Scratch/fr/blog/">Blog</a></li>
<li><a href="/Scratch/fr/softwares/">Softwares</a></li>
<li><a href="/Scratch/fr/about/">À propos</a></li></ul>
</div>
<div class="flush"></div>
<hr/>
<div id="next_before_articles">
<div id="previous_articles">
articles précédents
<div class="previous_article">
<a href="/Scratch/fr/blog/programming-language-experience/"><span class="nicer">«</span>&nbsp;Mon expérience avec les languages de programmation</a>
</div>
<div class="previous_article">
<a href="/Scratch/fr/blog/Learn-Vim-Progressively/"><span class="nicer">«</span>&nbsp;Apprenez Vim Progressivement</a>
</div>
<div class="previous_article">
<a href="/Scratch/fr/blog/A-more-convenient-diff/"><span class="nicer">«</span>&nbsp;Un diff plus pratique</a>
</div>
</div>
<div id="next_articles">
articles suivants
<div class="next_article">
<a href="/Scratch/fr/blog/Yesod-excellent-ideas/">Les idées de yesod&nbsp;<span class="nicer">»</span></a>
</div>
<div class="next_article">
<a href="/Scratch/fr/blog/SVG-and-m4-fractals/">Accroître le pouvoir des languages déficients.&nbsp;<span class="nicer">»</span></a>
</div>
<div class="next_article">
<a href="/Scratch/fr/blog/Yesod-tutorial-for-newbies/">Site en Haskell&nbsp;<span class="nicer">»</span></a>
</div>
</div>
<div class="flush"></div>
</div>
</div>
<div id="bottom">
<div>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.fr">Droits de reproduction ©, Yann Esposito</a>
</div>
<div id="lastmod">
Écrit le : 28/09/2011
modifié le : 26/10/2011
</div>
<div>
Site entièrement réalisé avec
<a href="http://www.vim.org">Vim</a>
et
<a href="http://nanoc.stoneship.org">nanoc</a>
</div>
<div>
<a href="/Scratch/fr/validation/">Validation</a>
<a href="http://validator.w3.org/check?uri=referer"> [xhtml] </a>
.
<a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3"> [css] </a>
.
<a href="http://validator.w3.org/feed/check.cgi?url=http%3A//yannesposito.com/Scratch/fr/blog/feed/feed.xml">[rss]</a>
</div>
</div>
<div class="clear"></div>
</div>
</body>
</html>