2011-09-27 15:11:40 +00:00
<?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" / >
2011-10-26 08:49:00 +00:00
< meta name = "keywords" content = "zsh, map, foldr, filter, functional, programming, higher order functions" >
2011-09-27 15:11:40 +00:00
< 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" / >
2012-04-02 21:43:39 +00:00
< link rel = "stylesheet" type = "text/css" href = "/Scratch/css/solarized.css" / >
2011-09-27 15:11:40 +00:00
< link rel = "stylesheet" type = "text/css" href = "/Scratch/css/idc.css" / >
2012-05-02 15:43:56 +00:00
< link href = 'http://fonts.googleapis.com/css?family=Inconsolata' rel = 'stylesheet' type = 'text/css' >
2011-09-27 15:11:40 +00:00
< link rel = "alternate" type = "application/rss+xml" title = "RSS" href = "http://feeds.feedburner.com/yannespositocomfr" / >
2011-09-30 08:16:57 +00:00
< 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/" / >
2011-09-27 15:11:40 +00:00
< 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 >
2012-05-02 15:43:56 +00:00
< script type = "text/javascript" src = "/Scratch/js/highlight/highlight.pack.js" > < / script >
< script type = "text/javascript" src = "/Scratch/js/article.js" > < / script >
2011-09-27 15:11:40 +00:00
<!-- [if lt IE 9]>
< script src = "http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js" > < / script >
<![endif]-->
2011-09-30 08:16:57 +00:00
< title > Fonctions d'ordre supérieur en zsh< / title >
2011-09-27 15:11:40 +00:00
< / head >
2011-10-18 22:30:00 +00:00
< body lang = "fr" class = "article" >
2011-09-27 15:11:40 +00:00
< script type = "text/javascript" > / / < ! [ C D A T A [
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" > ↓ Menu ↓ < / a > < / div >
< div id = "choixlang" >
< a href = "/Scratch/en/blog/Higher-order-function-in-zsh/" onclick = "setLanguage('en')" > in English< / a >
< / div >
2011-09-28 15:45:28 +00:00
< div class = "flush" > < / div >
2011-09-27 15:11:40 +00:00
< / div >
< div id = "titre" >
< h1 >
2011-09-30 08:16:57 +00:00
Fonctions d'ordre supérieur en zsh
2011-09-27 15:11:40 +00:00
< / h1 >
< / div >
< div class = "flush" > < / div >
< div class = "flush" > < / div >
< div id = "afterheader" >
< div class = "corps" >
2011-09-28 15:45:28 +00:00
< p > < img alt = "Title image" src = "/Scratch/img/blog/Higher-order-function-in-zsh/main.jpg" / > < / p >
2011-09-27 15:11:40 +00:00
< div class = "intro" >
2012-05-03 09:21:34 +00:00
< p > < span class = "sc" > < abbr title = "Trop long à lire" > tlàl< / abbr > : < / span > des fonctions d’ ordres supérieurs en zsh.< / p >
2011-09-27 15:11:40 +00:00
< / div >
2012-05-03 09:21:34 +00:00
< p > Tout d’ abord, pourquoi c’ est important d’ avoir ces fonctions.
Plus je programmais avec zsh plus j’ essayais d’ avoir un style fonctionnel.< / p >
2011-09-27 15:11:40 +00:00
2012-05-03 09:21:34 +00:00
< p > Le minimum pour pouvoir avoir du code plus lisible c’ est de posséder les fonctions < code > map< / code > , < code > filter< / code > et < code > fold< / code > .< / p >
2011-09-27 15:11:40 +00:00
< 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 :< / p >
2011-09-28 15:47:13 +00:00
< p > Avant ⇒< / p >
2012-05-02 15:43:56 +00:00
< pre > < code class = "zsh" > # for each directory in projects dir
for toProject in /path/to/projects/*(/N); do
# toProject is /path/to/projects/foo
# project become foo (:t for tail)
project=${toProject:t}
for toResource in $toProject/resources/*.gif(.N); do
convert $toResource ${toResource:r}.png & & \
\rm -f $toResource
done
done
< / code > < / pre >
2011-09-27 15:11:40 +00:00
2011-09-29 10:34:44 +00:00
< ul >
2012-05-03 09:21:34 +00:00
< li > Le < code > (/N)< / code > permet de sélectionner seulement les répertoires sans casser la boucle s’ il n’ y a pas de “ match” .< / li >
< li > Le < code > (.N)< / code > permet de sélection seulement les fichiers, aussi sans tout arréter s’ il ne trouve rien.< / li >
< li > Le < code > :t< / code > signfie “ tail” ; si < code > toto=/path/to/file.ext< / code > alors < code > ${toto:t}=file.ext< / code > .< / li >
2011-09-29 10:34:44 +00:00
< / ul >
2011-09-27 15:11:40 +00:00
< p > Après< / p >
2012-05-02 15:43:56 +00:00
< pre > < code class = "zsh" > gif_to_png() { convert $1 ${1:r}.png & & \rm -f $1 }
2011-09-28 15:47:13 +00:00
2012-05-02 15:43:56 +00:00
handle_resources() { map gif_to_png $1/resources/*.gif(.N) }
2011-09-28 15:47:13 +00:00
2011-09-27 15:11:40 +00:00
map handle_resources /path/to/projects/*(/N)
2012-05-02 15:43:56 +00:00
< / code > < / pre >
2011-09-27 15:11:40 +00:00
< p > Plus de bloc !
2012-05-03 09:21:34 +00:00
Oui, c’ est un poil plus difficile à lire pour les non initiés.
Mais c’ est à la fois plus concis et plus robuste.< / p >
2011-09-27 15:11:40 +00:00
< 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 >
2011-09-28 15:45:28 +00:00
< p > Before ⇒< / p >
2012-05-02 15:43:56 +00:00
< pre > < code class = "zsh" > for toProject in Projects/*; do
project=$toProject:t
if print -- project | grep -v s > /dev/null
then
print $project
for toResource in $toProject/*(.N); do
if print -- ${toResource:t} | grep $project > /dev/null; then
print -- "X $toResource"
fi
done
fi
done
< / code > < / pre >
2011-09-27 15:11:40 +00:00
2011-09-28 15:45:28 +00:00
< p > After ⇒< / p >
2011-09-27 15:11:40 +00:00
2012-05-02 15:43:56 +00:00
< pre > < code class = "zsh" > contain_no_s() { print $1 | grep -v s }
2011-09-28 15:45:28 +00:00
2011-09-27 15:11:40 +00:00
function verify_file_name {
2012-05-02 15:43:56 +00:00
local project=$1:t
contains_project_name() { print $1:t | grep $project }
map "print -- X" $(filter contains_project_name $1/*(.N))
2011-09-27 15:11:40 +00:00
}
2011-09-28 15:45:28 +00:00
2012-05-02 15:43:56 +00:00
map verify_file_name $( filter contain_no_s Projects/* )
< / code > < / pre >
2011-09-27 15:11:40 +00:00
2011-09-28 15:47:13 +00:00
< p > La première version peu paraître plus facile à lire.
2012-05-03 09:21:34 +00:00
Mais la seconde est plus bien supérieure en terme d’ architecture.
Je ne veux pas discuster ici pourquoi c’ est mieux.
Je vous demande simplement de me croire quand je dis que l’ approche fonctionnelle est supérieure.< / p >
2011-09-28 15:47:13 +00:00
2012-05-03 09:21:34 +00:00
< p > Actuellement il me manque une fonction lambda, si quelqu’ un à une idée elle serait la bienvenue.
2011-09-28 15:47:13 +00:00
Je ne sais pas encore comment créer facilement des fonctions anonymes.< / p >
< p > Voici le code source :< / p >
2011-09-27 15:11:40 +00:00
2012-05-02 15:43:56 +00:00
< div class = "codefile" > < a href = "/Scratch/fr/blog/Higher-order-function-in-zsh/code/functional.sh" > ➥ functional.sh< / a > < / div >
2011-09-28 15:45:28 +00:00
2012-05-02 15:43:56 +00:00
< pre > < code class = "zsh" > #!/usr/bin/env zsh
2011-09-28 15:45:28 +00:00
2012-05-02 15:43:56 +00:00
# Provide higer-order functions
# usage:
#
# $ foo(){print "x: $1"}
# $ map foo a b c d
# x: a
# x: b
# x: c
# x: d
2011-09-28 15:45:28 +00:00
function map {
2012-05-02 15:43:56 +00:00
local func_name=$1
2011-09-28 15:45:28 +00:00
shift
2012-05-02 15:43:56 +00:00
for elem in $@; print -- $(eval $func_name $elem)
2011-09-28 15:45:28 +00:00
}
2012-05-02 15:43:56 +00:00
# $ bar() { print $(($1 + $2)) }
# $ fold bar 0 1 2 3 4 5
# 15
# -- but also
# $ fold bar 0 $( seq 1 100 )
2011-09-28 15:45:28 +00:00
function fold {
2012-05-02 15:43:56 +00:00
if (($#< 2)) {
print -- "ERROR fold use at least 2 arguments" > & 2
2011-09-28 15:45:28 +00:00
return 1
}
2012-05-02 15:43:56 +00:00
if (($#< 3)) {
print -- $2
2011-09-28 15:45:28 +00:00
return 0
2012-05-02 15:43:56 +00:00
} else {
2011-09-28 15:45:28 +00:00
local acc
local right
2012-05-02 15:43:56 +00:00
local func_name=$1
local init_value=$2
local first_value=$3
2011-09-28 15:45:28 +00:00
shift 3
2012-05-02 15:43:56 +00:00
right=$( fold $func_name $init_value $@ )
acc=$( eval "$func_name $first_value $right" )
print -- $acc
2011-09-28 15:45:28 +00:00
return 0
}
}
2012-05-02 15:43:56 +00:00
# usage:
#
# $ baz() { print $1 | grep baz }
# $ filter baz titi bazaar biz
# bazaar
2011-09-28 15:45:28 +00:00
function filter {
2012-05-02 15:43:56 +00:00
local predicate=$1
2011-09-28 15:45:28 +00:00
local result
typeset -a result
shift
2012-05-02 15:43:56 +00:00
for elem in $@; do
if eval $predicate $elem > /dev/null; then
result=( $result $elem )
fi
done
print $result
2011-09-28 15:45:28 +00:00
}
2012-05-02 15:43:56 +00:00
< / code > < / pre >
2011-09-28 15:45:28 +00:00
2011-09-27 15:11:40 +00:00
< / div >
2012-04-10 13:56:34 +00:00
< div id = "social" >
< div class = "left" > < a href = "https://twitter.com/share" class = "twitter-share-button" data-via = "yogsototh" > Tweet< / a >
< script > ! function ( d , s , id ) { var js , fjs = d . getElementsByTagName ( s ) [ 0 ] ; if ( ! d . getElementById ( id ) ) { js = d . createElement ( s ) ; js . id = id ; js . src = "//platform.twitter.com/widgets.js" ; fjs . parentNode . insertBefore ( js , fjs ) ; } } ( document , "script" , "twitter-wjs" ) ; < / script >
< / div >
< div class = "left" > < div class = "g-plusone" data-size = "medium" data-annotation = "inline" data-width = "106" > < / div >
< script type = "text/javascript" >
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
< / script >
< / div >
< div class = "flush" > < / div >
< / div >
2011-09-27 15:11:40 +00:00
< 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();
}
2012-04-10 13:56:34 +00:00
document.write('< div id = "clickcomment" > Commentaires & Partage< / div > ');
2011-09-27 15:11:40 +00:00
< / script >
< div class = "flush" > < / div >
2012-04-10 13:56:34 +00:00
2011-09-27 15:11:40 +00:00
< 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
2011-09-28 15:47:13 +00:00
< div class = "previous_article" >
2011-09-30 08:16:57 +00:00
< a href = "/Scratch/fr/blog/programming-language-experience/" > < span class = "nicer" > «< / span > Mon expérience avec les languages de programmation< / a >
2011-09-28 15:47:13 +00:00
< / div >
2011-09-27 15:11:40 +00:00
< div class = "previous_article" >
< a href = "/Scratch/fr/blog/Learn-Vim-Progressively/" > < span class = "nicer" > «< / span > Apprenez Vim Progressivement< / a >
< / div >
< div class = "previous_article" >
2011-09-28 16:05:55 +00:00
< a href = "/Scratch/fr/blog/A-more-convenient-diff/" > < span class = "nicer" > «< / span > Un diff plus pratique< / a >
2011-09-27 15:11:40 +00:00
< / div >
< / div >
< div id = "next_articles" >
articles suivants
2011-10-18 22:30:00 +00:00
< div class = "next_article" >
< a href = "/Scratch/fr/blog/Yesod-excellent-ideas/" > Les idées de yesod < span class = "nicer" > »< / span > < / a >
< / div >
2011-09-27 15:11:40 +00:00
2011-11-16 12:08:26 +00:00
< div class = "next_article" >
2011-11-16 12:30:46 +00:00
< a href = "/Scratch/fr/blog/SVG-and-m4-fractals/" > Accroître le pouvoir des languages déficients. < span class = "nicer" > »< / span > < / a >
2011-11-16 12:08:26 +00:00
< / div >
2011-09-27 15:11:40 +00:00
2012-01-11 20:40:22 +00:00
< div class = "next_article" >
< a href = "/Scratch/fr/blog/Yesod-tutorial-for-newbies/" > Site en Haskell < span class = "nicer" > »< / span > < / a >
< / div >
2011-09-27 15:11:40 +00:00
< / div >
< div class = "flush" > < / div >
< / div >
< / div >
< div id = "bottom" >
2012-04-02 21:43:39 +00:00
< div >
2012-04-10 13:56:34 +00:00
< a href = "https://twitter.com/yogsototh" > Follow @yogsototh< / a >
2012-04-02 21:43:39 +00:00
< / div >
2011-09-27 15:11:40 +00:00
< 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" >
2011-09-28 15:47:13 +00:00
Écrit le : 28/09/2011
2012-05-02 15:43:56 +00:00
modifié le : 26/04/2012
2011-09-27 15:11:40 +00:00
< / 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 >
< div class = "clear" > < / div >
< / div >
< / body >
< / html >