[Haskell-cafe] Better versions of this code

Martijn Schrage martijn at oblomov.com
Thu Oct 24 10:23:44 UTC 2013

By using a list comprehension you can keep everything together and avoid 
the zipping and unzipping. It also lets you get rid of the partiality 
introduced by head. See http://lpaste.net/94731 for a new version.

There's a couple more changes, some of which might be a matter of taste:
   - variable renames: update ~> updateLine, target ~> isIndented
   - if expression instead of boolean guard
   - introduced a couple of $'s to reduce parentheses
   - no partial fromJust functions in updateLine
   - case for pattern matching in main


On 24-10-13 04:43, Joey Adams wrote:
> On Wed, Oct 23, 2013 at 11:43 AM, Tyson Whitehead 
> <twhitehead at gmail.com <mailto:twhitehead at gmail.com>> wrote:
>     Hey All,
>     I wrote some quick code to change mediawiki preformatted text
>     (adjacent lines begining with a ' ') to nowiki blocks (first line
>     with a ' ' and rest enclosed in <nowiki>...</nowiki> quotes).
>     http://lpaste.net/94688
>     I frequently find myself pretty unsatisfied with this type of code
>     though.  Anyone have any rewrites that would help teach me how to
>     do this more elegantly in the future.
> My first reaction was: use function composition to get rid of all 
> those variables.  But this code is interesting because some 
> intermediate results are used multiple times.  Here is the dependency 
> graph: http://i.imgur.com/Smid5VZ.png (source file: 
> http://lpaste.net/94718).
> Before tackling the organization, I did some trivial refactoring: 
> http://lpaste.net/94717.  Namely:
>  * import Data.Function (on) instead of redefining 'on'.
>  * import Data.Text (Text) to avoid qualified import for T.Text 
> everywhere.
>  * Use the OverloadedStrings extension to say "hello" instead of 
> T.pack "hello".
>  * Back off the indentation in 'update' by putting the first guard on 
> a new line.
>  * Move 'update' to a separate definition so we know it doesn't need 
> any extra variables from 'replace'.
>  * Use T.concat instead of multiple T.append calls, to make update 
> much more readable.  There's also the <> operator in Data.Monoid 
> (added in base 4.6).
>  * Use map instead of fmap so it's clear we're working with a list. 
>  Not everyone will agree with me on this.
>  * Use newlines to group the steps of the process.
> Also, be wary of partial functions (functions that fail for some 
> inputs) like 'head' and 'fromJust'.  They're fine for quick scripts, 
> but not for code other people will be using.  When a program crashes 
> with "Prelude.head: empty list", it makes all of us look bad. 
>  Instead, favor pattern matching or functions like 'fromMaybe' and 
> 'maybe'.  On the other hand, 'head' and 'groupBy' are okay to use 
> together because 'groupBy' returns lists that are all non-empty.
> I'll say it again: partial functions are *fine* for quick scripts. 
>  When you are the only one running the program, you can save a lot of 
> time by making assumptions about the input.
> All that's left is the fun part: making 'replace' easier to 
> understand.  I think the key is to move the "Group lines according to 
> classification" logic to a separate function.  The other steps of 
> 'replace' have simple code, so this should help a lot.
> Hope this helps,
> -Joey
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

Martijn Schrage, Oblomov Systems
06-31920188 | martijn at oblomov.com | http://www.oblomov.com
LinkedIn: http://www.linkedin.com/pub/martijn-schrage/6/677/505

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20131024/1648a86d/attachment.html>

More information about the Haskell-Cafe mailing list