scratch/output/Scratch/en/blog/Higher-order-function-in-zsh/index.html
Yann Esposito (Yogsototh) 5edbdd4401 Recompiled with Xth in sup.
2011-11-16 13:14:39 +01:00

336 lines
No EOL
18 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/yannespositocomen"/>
<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>Higher order function in zsh</title>
</head>
<body lang="en" class="article">
<script type="text/javascript">// <![CDATA[
document.write('<div id="blackpage"><img src="/Scratch/img/loading.gif" alt="loading..."/></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/fr/blog/Higher-order-function-in-zsh/" onclick="setLanguage('fr')">en Français</a>
</div>
<div class="flush"></div>
</div>
<div id="titre">
<h1>
Higher order function in 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="Too long; didn't read">tl;dr</abbr>: </span> some simple implementation of higher order function for zsh.</p>
</div>
<p>Why is it important to have these functions?
Simply because, the more I programmed with zsh the more I tended to work using functional programming style.</p>
<p>The minimal to have better code are the functions <code>map</code>, <code>filter</code> and <code>fold</code>.</p>
<p>Lets compare.
First a program which convert all gif to png in many different directories of different projects.</p>
<p>Before ⇒</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>The <code>(/N)</code> means to select only directory and not to crash if there isnt any.</li>
<li>The <code>(.N)</code> means to select only files and not to crash if there isnt any.</li>
<li>The <code>:t</code> means tail; if <code>toto=/path/to/file.ext</code> then <code>${toto:t}=file.ext</code>.</li>
</ul>
<p>After ⇒</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>No more bloc!
It might be a little bit harder to read if youre not used to functional programming notation.
But it is more concise and robusts.</p>
<p>Another example with some tests.</p>
<p>Find all files in project not containing an <code>s</code> which their name contains their project name:</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>Also, the first verstion is a bit easier to read.
But the second one is clearly far superior in architecture.
I dont want to argue why here.
Just believe me that the functional programming approach is superior.</p>
<p>Actually I lack the lambda operator.
If someone has an idea on how to create anonymous functions, just tell me, thanks.</p>
<p>Here is the source code:</p>
<div class="code"><div class="file"><a href="/Scratch/en/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/yannespositocomen">
Subscribe
</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">Comments</div>');
</script>
<div class="flush"></div>
<div class="corps" id="comment">
<h2 class="first">comments</h2>
<noscript>
You must enable javascript to comment.
</noscript>
<script type="text/javascript">
var idcomments_acct = 'a307f0044511ff1b5cfca573fc0a52e7';
var idcomments_post_id = '/Scratch/en/blog/Higher-order-function-in-zsh/';
var idcomments_post_url = 'http://yannesposito.com/Scratch/en/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/en/">Home</a></li>
<li><a href="/Scratch/en/blog/">Blog</a></li>
<li><a href="/Scratch/en/softwares/">Softwares</a></li>
<li><a href="/Scratch/en/about/">About</a></li></ul>
</div>
<div class="flush"></div>
<hr/>
<div id="next_before_articles">
<div id="previous_articles">
previous entries
<div class="previous_article">
<a href="/Scratch/en/blog/programming-language-experience/"><span class="nicer">«</span>&nbsp;Programming Language Experience</a>
</div>
<div class="previous_article">
<a href="/Scratch/en/blog/Learn-Vim-Progressively/"><span class="nicer">«</span>&nbsp;Learn Vim Progressively</a>
</div>
<div class="previous_article">
<a href="/Scratch/en/blog/A-more-convenient-diff/"><span class="nicer">«</span>&nbsp;A more convenient diff</a>
</div>
</div>
<div id="next_articles">
next entries
<div class="next_article">
<a href="/Scratch/en/blog/Yesod-excellent-ideas/">Yesod excellent ideas&nbsp;<span class="nicer">»</span></a>
</div>
<div class="next_article">
<a href="/Scratch/en/blog/SVG-and-m4-fractals/">SVG and m4 fractals&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/">Copyright ©, Yann Esposito</a>
</div>
<div id="lastmod">
Created: 09/28/2011
Modified: 10/26/2011
</div>
<div>
Entirely done with
<a href="http://www.vim.org">Vim</a>
and
<a href="http://nanoc.stoneship.org">nanoc</a>
</div>
<div>
<a href="/Scratch/en/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/en/blog/feed/feed.xml">[rss]</a>
</div>
</div>
<div class="clear"></div>
</div>
</body>
</html>