https://wiki.haskell.org/api.php?action=feedcontributions&user=B7j0c&feedformat=atomHaskellWiki - User contributions [en]2024-03-28T19:51:03ZUser contributionsMediaWiki 1.35.5https://wiki.haskell.org/index.php?title=Hackage_wiki_page_per_project_discussion&diff=32437Hackage wiki page per project discussion2009-12-13T04:02:16Z<p>B7j0c: brad clawsie adding support note</p>
<hr />
<div>== Purpose of this page ? ==<br />
collect thoughts about whether we should provide a wiki page (and maybe even more advanced features such as bug trackers) for all projects hosted on hackage<br />
<br />
I'll post a link to this page to haskell-cafe so everyone should participate<br />
<br />
== Why a Wiki ==<br />
We do have about 1500 packages on hackage. Hackage was made live easier.<br />
While packaging some packages for nix (using [[Hack-Nix]]) I had to write some patches.<br />
<br />
If you have a patch what to do?<br />
Duncan Coutts proposed contacting the maintainer. If you don't receive replies within a time frame write to the haskell-cafe mailinglist. If you can't find him become the new maintainer.<br />
<br />
While contacting the maintainer works very well within 3 days in most cases there are situations where maintainers can't reply because they are on holiday or got very busy.. In these cases I'd like to put my patch somewhere so that others can find them.<br />
<br />
== What could a wiki page be used for? ==<br />
<br />
<br />
a) patches (which are removed when maintainers integrate them upstream)<br />
<br />
b) Howtos and pitfalls (written by users or maintainers)<br />
<br />
c) references to similar projects pointing out differences.<br />
<br />
d) a smart lazy changelog. If a user hits a change he can add this to the<br />
wiki so that others can find out faster which version constraints to<br />
add to their .cabal file.<br />
<br />
This looks like this:<br />
2.20: renamed foo to bar.<br />
<br />
2.48: type change of iwillneverChange :: Int to Maybe Int<br />
<br />
e) a list of changes which will go into the next release of a package.<br />
This may help you figuring out whether you should download the darcs repository.<br />
<br />
f) many other ideas I can't think about yet.<br />
<br />
...<br />
<br />
<br />
== implementation details: ==<br />
<br />
design could look like this:<br />
http://mawercer.de/~marc/hackage-link-example.jpg<br />
<br />
The link would point to the haskell wiki having the url suffix /project-name.<br />
<br />
== When a wiki page can replace a .cabal file update ==<br />
<br />
* naturally it takes some time until most recent cabal updates are used by mainstream.. Eg there is a way to add repository locations now.. But have a look at [http://hackage.haskell.org/packages/archive/happy/1.18.4/happy.cabal happy.cabal] and smile :) Btw: I adopted this usage of the source-repository field for one project.<br />
<br />
* minor dependency changes<br />
<br />
* tell users about experimental branches<br />
<br />
* it's easier to provide important information such as:<br />
<br />
"This package is superseded by XY because: ..."<br />
<br />
** We already have a mechanism to deprecate packages or to mark them as superseded. --[[User:DuncanCoutts|DuncanCoutts]] 00:25, 12 December 2009 (UTC)<br />
<br />
[[User:MarcWeber|Marc Weber]]: Can you explain how this works or point me to the documentation?<br />
<br />
The main point about this wiki idea is that you can attach arbitrary information and you don't have to wait for anyone to do so.<br />
Get things done. Provide patches. Link them on the wiki.<br />
Come back later and discuss your proposals with the maintainer.<br />
Keep summaries of discussions on subjects accesible by everyone.<br />
...<br />
<br />
Of course I know that the maintainers are the people doing the real work.<br />
But look at it from a different view: Having such a forum for all projects by default also means that a maintainer can let others do some of the work knowing that they don't have to reply within some days.<br />
<br />
The wiki can host all information which may be useful but which wasn't foreseen by hackage or cabal devs. We must keep agile and move forward only.<br />
<br />
== Concerns ==<br />
<br />
My (DuncanCoutts) concern is about the consent from package authors. Hackage is a social bargain. We ask package authors to distribute their work through hackage because it provides benefits to the community. If we impose too much on package authors then they may decide it's just not worth it.<br />
<br />
In particular, if we automatically create a wiki page for every package then we are imposing additional obligations on package authors. As a package author I might be concerned that this wiki page duplicates an existing home page or bug tracking system. If there's a wiki page about my project then I am effectively obligated to check it from time to time, since users will inevitably report bugs etc there. It is that extra obligation that package authors may resent.<br />
<br />
There is no problem with such a feature being opt-in, but whether it is something we require and impose on package authors needs much more of a social consensus before we go ahead.<br />
<br />
Reply [[User:MarcWeber|Marc Weber]]: Everybody knows that it is wiki content and will take care.<br />
<br />
About effort: Note that package authors can watch their wiki pages easily.<br />
Authors and maintainers already do the hard work. Watching a wiki page is not mach work compared to writing a library. But they may find wiki contents of foreign projects that useful that they provide some contents their selves<br />
<br />
== concern "The wiki will be outdated" ==<br />
True. Every user must know that wikis naturally are out of date :)<br />
But the question is: Can one wiki page (containing an example)<br />
generate more value than some outdated pages cause damage to you?<br />
<br />
It's hard to say because haskellwiki wiki pages can be found when searching from the start page as well.<br />
<br />
Maybe we can ask users to add the package version so that users will see themselves that content is outdated?<br />
<br />
<br />
Don't think about other people. Think about yourself: Do you mind reading some outdated wiki pages? Do you appreciate the valuable contents which will be exist as well? If you don't mind reading some outdated pages and if you'd like to see more examples about how to use packages you basically support this idea!<br />
Let's not forget that haskell.org is a wiki itself. And naturally parts are outdated as well. You still don't want to miss it, do you?<br />
<br />
== wiki alternatives ==<br />
If content isn't put on a wiki what do people do instead?<br />
* They may do nothing (bad)<br />
* They may write a blog (bad because others don't find it or because content gets out of date). Which way is more likely providing you with valuable information: A blog found by google or an attached wiki page people can keep up to date?<br />
* They may write to the mailinglist. Things are archived forever. On the wiki they are as well but not only a small amount of visitors ever looks at the history of a page..<br />
<br />
== my project already has a wiki ..==<br />
Fine. In this case the haskellwiki wiki page will only have one link telling the user about your page.<br />
<br />
== progress and feedback ==<br />
I've send a short mail to about 100 maintainers to get to know what they think about this idea.<br />
<br />
+++ : I support the idea<br />
<br />
++ : I support but want opt-out<br />
<br />
+ : I support but I want opt-in<br />
<br />
- : I don't like the idea even if there was a warning such as<br />
"This content is contributed by maintainers and users and may be out of date."<br />
If you vote "-" make sure you've read "wiki alternatives". You can clean up the wiki page. You can't clean up foreign blogs.<br />
<br />
Consider adding your name only for spam reasons (but send your emal address to marco-oweber@gmx.de so that I can associate them with packages on hackage to got to know who didn't reply)<br />
<br />
I support this idea:<br />
* marco-oweber@gmx.de (Marc Weber +++)<br />
* clawsie@fastmail.fm (Brad Clawsie +++)<br />
<br />
I do mind:<br />
* EvanMartin (exactly what Duncan wrote -- I don't have time to vet a third-party page and keep it up to date; I have seen obsolete wikis for too many projects in my time. If I want to use a wiki I could just set it as the home page for my project. Consider adding a "wiki" link to the package description format.)<br />
<br />
I don't care:<br />
*<br />
<br />
I won't tell you:<br />
*<br />
<br />
== Notes ==<br />
You can watch this page</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive&diff=21724Xmonad/Config archive2008-07-10T05:14:43Z<p>B7j0c: </p>
<hr />
<div>{{xmonad}}<br />
<br />
==xmonad configuration examples==<br />
<br />
Configuration files (Config.hs for xmonad < 0.5, xmonad.hs for xmonad >= 0.5)<br />
<br />
Many config files marked as 0.5 probably work in 0.6 as well; give it a try and ask on the #xmonad IRC channel on freenode.org if you have problems.<br />
<br />
For more screenshots see the [[Xmonad/Screenshots]] archive.<br />
<br />
;[[/Template xmonad.hs]] (0.6)<br />
:The default xmonad settings, in the form of a template, so you can easily edit and replace any values.<br />
<br />
;[[/Don's xmonad.hs]] (0.5,0.6,0.7)<br />
:[[/Don's Config.hs]] (0.4)<br />
:colours, use custom terminal, dynamicLogDzen<br />
[[Image:Xmonad-screen-dons-code.png|center|200px]]<br />
<br />
;[[/Gwern's Config.hs]] (0.7-; darcs)<br />
:[[/Gwern's Config.hs (0.4)]] (old)<br />
:Ratpoison-y keybindings; example usage of XSelection.<br />
<br />
;[[/twifkak's xmonad.hs]] (0.5)<br />
:[[/twifkak's Config.hs]] (0.4)<br />
:modMask = mod4Mask; noBorders tabbed layout; keybindings for dzen, rotview, swapworkspaces, windowbringer, and windownavigation; urgencyhook (only in darcs xmonad).<br />
<br />
;[[/nomeatas Config.hs]] (0.4)<br />
:modMaks = mod4Mask; gnome-stuff<br />
<br />
;[[/David Roundy's xmonad.hs]] (0.5)<br />
:Combo config for small screen + xclock. Requires the xmonad-library branch, so not for the faint of heart. This config also keeps mod=mod1, and therefore moves a number of key bindings to non-standard locations (my laptop has no spare modifier keys).<br />
[[Image:droundy-config.png|center|200px]]<br />
<br />
;[[/Brent Yorgey's xmonad.hs]] (0.6)<br />
:[[/Brent Yorgey's darcs xmonad.hs]] (darcs)<br />
:modMask = mod4Mask; DynamicLog, RotView, ViewPrev, WindowNavigation, ToggleLayouts (toggle full screen mode), UrgencyHook + dzen, FlexibleManipulate, a bunch of Prompts, Submap, Search, and a few others, with keybindings for all! (Warning: lots of non-standard keybindings. =)<br />
[[Image:byorgey-config.png|center|200px]]<br />
<br />
;[[/Robert Manea's xmonad.hs]] (0.5)<br />
:[[/Robert Manea's Config.hs and support scripts]] (0.4)<br />
:Customized DynamicLog and ShellPrompt, ManageDock, some efforts to make the colors of all components go together well<br />
0.4 screenshot: [[Image:rob-config.png|center|400px]]<br />
0.5 screenshot: [[Image:Xmonad_shellprompt_newconf.png|center|400px]]<br />
<br />
;[[/Eric Mertens' xmonad.hs]] (0.5)<br />
:[[/Eric Mertens's Config.hs]] (0.4)<br />
:Customized DynamicLog, ShellPrompt, TilePrime, Dual-head and an effort to make the statusbar similar to DWM.<br />
[[Image:glguy-config.jpg|center|400px]]<br />
<br />
;[[/vvv's xmonad.hs]] (0.5-0.7)<br />
:[[/vvv's Config.hs]] (0.4)<br />
:CustomKeys, CycleWS, {Shell,Ssh,Man}Prompt, Submap, DynamicWorkspaces, NoBorders, and ion-like status bar written in nonkosher Perl.<br />
[[Image:vvv-config.png|center|200px]]<br />
<br />
;[[/Andrea Rossato's xmonad.hs]] (0.5)<br />
:[[/arossato's Config.hs]] (0.4)<br />
:Tabbed, Xmobar with DynamicLog, (Shell|Ssh|Man)Prompt.<br />
[[Image:Arossato-config.png|center|200px]]<br />
<br />
;[[/Octoploid's xmonad.hs]] (0.7)<br />
:Xmobar with customized DynamicLog, CycleWS with custom keys, colors, terminal, golden ratio<br />
[[Image:Octoploid_conf.png|center|200px]]<br />
<br />
;[[/Ray's xmonad.hs]] (0.5)<br />
:DynamicLog, custom manageHook, changed from default terminal, border colors, prompts, and layouts. Pseudo-Haskell dzen statusbar with greek letters for workspace names.<br />
[[Image:Ray-config.png|center|200px]]<br />
<br />
;[[/nattfodd's xmonad.hs]] (0.7/darcs)<br />
:DynamicLog, smartBorders, French keyboard, defaultGap, urgencyHook in workspace toolbar and some prompts.<br />
[[Image:Nattfodd-xmonad-0.7.png|center|200px]]<br />
<br />
;[[/deifl's xmonad.hs]] (0.5)<br />
:DynamicLog, WindowBringer, CopyWindow, ResizableTile, Tabbed layout. not default terminal, changed colors and some instances of dzen.<br />
Clean: [[Image:D_xmonad_clear.jpg|center|200px]]<br />
Populated: [[Image:D_xmonad_full.jpg|center|200px]]<br />
<br />
;[[/Xilon's xmonad.hs]] (0.5)<br />
:Simple and clean setup with dzen and a tray. Dzen with workspaces uses UrgencyHook for Urgent windows.<br />
[[Image:xilon-config.png|center|200px]]<br />
<br />
; [[/skorpan's xmonad.hs]] (0.7)<br />
: Pretty clean setup. I use conky-cli with dzen2 at the bottom of the screenshot, which is not included here.<br />
[[Image:Skorpan.png|center|200px]]<br />
<br />
;[[/loupgaroublonds xmonad.hs]] (0.5)<br />
: mostly a stock config but with support for gnome and my cat<br />
[[Image:loupgaroublond-config.png|center|200px]]<br />
<br />
;[[/cce xmonad.hs]] (0.5)<br />
: alt+enter full screen, alt+hjkl to navigate, many remapped keys<br />
<br />
;[[/entropies xmonad.hs]] (0.5)<br />
: windows as meta key, fullscreen & noborders on keypress for client. custom keybindings. magnifier.<br />
[[Image:entropie-config.png|center|200px]]<br />
<br />
; [[/brad's xmonad.hs]] (0.7)<br />
: very basic, just some cosmetic and key-shortcut changes<br />
[[Image:brad.png|center|200px]]<br />
<br />
; [[/Lee Aylward's xmonad.hs]] (0.5)<br />
: Resizable Tall, NoBorders, dzen DynamicLog, rhythmbox control shortcuts, windows key<br />
[[Image:leeaylward.png|center|400px]]<br />
<br />
; [[/oxymor00n's xmonad.hs]] (darcs)<br />
: [[/oxymor00n's xmobarrc]]<br />
: Tabbed layout, Floating Layout, xmobar, EZConfig for Emacs-like keybinding-definition, added some bindings for the mouse wheel (cycle focus and cycle workspaces), cycleWS-stuff that might be interesting for Xinerama-users,...<br />
[[Image:oxymor00n-xmonad.png|center|200px]]<br />
<br />
<br />
; [[/Andrea Spada xmonad.hs]] (0.6)<br />
: Tall, Resizable Mosaic and Combo, EvmhDesktops, additional keybindings - Work In Progress...<br />
<br />
; [[/Wfarr's xmonad.hs]] (0.6/darcs)<br />
: ResizableTall Layout using EZConfig, cycleWS, CopyWindows, and DZen to get some cool stuff happening.<br />
[[Image:Wfarrscreen1.png|center|200px]]<br />
<br />
; [[/lithis's xmonad.hs]] (darcs)<br />
; [[/lithis's xmobarrc]] (darcs)<br />
: The screenshot shows xmobar, two screens, a spiral layout, a tabbed layout, XFT fonts, and ShellPrompt with tab completion. The config also has pointer follows focus.<br />
[[Image:lithis-xmonad.png|center|200px]]<br />
<br />
; [[/andrewsw's xmonad.hs]] (0.6)<br />
; [[/andrewsw's .Xdefault]]<br />
: These screenshots show some compositing and nice transparent urxvt's with a circle layout and a magnified grid layout.<br />
<br />
[[Image:Xmonad-circle-comp.jpg|center|200px]]<br />
[[Image:Xmonad-mag-grid.jpg|center|200px]]<br />
<br />
; [[/sykopomp's xmonad.hs]] (darcs)<br />
; [[/sykopomp's xmonad.dv-vi.hs]]<br />
; This screeshot shows xfce-panel with pager + xmonad in a ResizableTall layout. Also using compositing and transparent urxvt's (thanks andrewsw) with bindings for changing transparency on focused window. Keybindings have been completely redone to be more similar to emacs-bindings (M-p and M-n for previous and next windows). The other config is an older config that uses the standard vi-like bindings, but translated by location to a dvorak layout.<br />
[[Image:xmonad-screen-xinerama-composite-xfce.jpg|center|200px]]<br />
<br />
; [[/sphynx's xmonad.hs]] (darcs)<br />
; Emacs-style keybindings, xmobar integration, XFT-fonts, ManageDocks, Tabbed layout, IM layout for Pidgin and Skype configured through PerWorkspace, Search extension for wikipedia, translation and google, usage of CopyWindow to 'make window always visible', Urgency hook, PerWorkspace usage, Scratchpad terminal, custom styles for prompt and borders.<br />
<br />
; [[/thoughtpolice's xmonad.hs]] (darcs)<br />
; [[/thoughtpolice's xmobarrc]] (0.9)<br />
; Emacs-esque keyboard bindings via EZConfig, dynamicLog with dzen, Submap google/hoogle/amazon/imdb/youtube/wikipedia searching, Shell & Ssh modules, slightly custom XPConfig and avoidStruts (ManageDocks.)<br />
<br />
; [[/Remi's xmonad.hs]] (0.7)<br />
; [[/Remi's .xmobarrc]] (0.8)<br />
; [[/Remi's .xinitrc]]<br />
: Lots of key bindings for destkop-navigation/moving, xmonad.hs-editing, music, next-N-windows-float-hack. xmobar integration and PerWorkspace Layouts. And a yet-to-be-published libmpd xmobar plugin.<br />
<br />
[[Image:Remi-xmonad-screenshot.png|center|200px]]<br />
<br />
; [[/TeXitoi's xmonad.hs]] (0.7)<br />
; French keyboard, ManageDock, EwmhDesktops. Minimal configuration file with Defaults not overwritten. Mist GTK theme is used.<br />
<br />
[[Image:Xmonad-xfce-panel.png|center|200px]]<br />
<br />
== Note on uploading ==<br />
<br />
To upload your config file, create some text on this page of the form:<br />
<br />
<nowiki>; [[/you Config.hs]]</nowiki><br />
<nowiki>: description of your setup</nowiki><br />
<br />
and save the page. This will create a new page under /you into which you<br />
can paste your Config.hs text. Wrap them in <nowiki><haskell></nowiki> and <nowiki></haskell></nowiki><br />
tags, to enable nice markup; add a nice category like <nowiki>[[Category:XMonad configuration]]</nowiki>, and upload. If you have an xmonad.hs for xmonad 0.5,<br />
upload that to<br />
<br />
<nowiki>; [[/you xmonad.hs]]</nowiki><br />
<br />
Images can be uploaded by clicking on the 'Upload file' link, and then<br />
referring to the uploaded image as, e.g.<br />
<br />
<nowiki>[[Image:you-config.png|center|200px]]</nowiki><br />
<br />
which will scale the image correctly for a thumbnail.<br />
<br />
[[Category:XMonad configuration]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=21723Xmonad/Config archive/brad's xmonad.hs2008-07-10T05:14:10Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified XMonad.Util.CustomKeys as C<br />
import qualified Data.Map as M<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = C.customKeys delkeys inskeys<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
where<br />
delkeys :: XConfig l -> [(KeyMask, KeySym)]<br />
delkeys XConfig {modMask = modm} =<br />
[ (modm, xK_b) ]<br />
<br />
inskeys :: XConfig l -> [((KeyMask, KeySym), X ())]<br />
inskeys conf@(XConfig {modMask = modm}) =<br />
let font = "Monospace"<br />
color = "-fg white -bg black"<br />
urxvt = "urxvt -vb +sb" in <br />
[ <br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_e), spawn <br />
("emacs --font \"" ++ font ++ "-14\" " ++ color)),<br />
((modm .|. shiftMask, xK_u), spawn <br />
(urxvt ++ " " ++ color ++ " -fn \"xft:" ++ font ++ <br />
":pixelsize=20\"")),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre></div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=21722Xmonad/Config archive/brad's xmonad.hs2008-07-10T05:13:46Z<p>B7j0c: upgrade for 0.7</p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified XMonad.Util.CustomKeys as C<br />
import qualified Data.Map as M<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = C.customKeys delkeys inskeys<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
where<br />
delkeys :: XConfig l -> [(KeyMask, KeySym)]<br />
delkeys XConfig {modMask = modm} =<br />
[ (modm, xK_b) ]<br />
<br />
inskeys :: XConfig l -> [((KeyMask, KeySym), X ())]<br />
inskeys conf@(XConfig {modMask = modm}) =<br />
let font = "Monospace"<br />
color = "-fg white -bg black"<br />
urxvt = "urxvt -vb +sb" in <br />
[ <br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_e), spawn <br />
("emacs --font \"" ++ font ++ "-14\" " ++ color)),<br />
((modm .|. shiftMask, xK_u), spawn <br />
(urxvt ++ " " ++ color ++ " -fn \"xft:" ++ font ++ <br />
":pixelsize=20\"")),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
<br />
[[Image:brad.png|center|200px]]</pre></div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=21459Network.Curl2008-06-25T05:53:34Z<p>B7j0c: add new sample</p>
<hr />
<div>This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.<br />
<br />
<h2>Trivial Use</h2><br />
<pre><br />
$ ghci<br />
Prelude> :m Network.Curl<br />
Prelude Network.Curl> let html = curlGetString "http://www.haskell.org/" []<br />
</pre><br />
<br />
<h2>External Examples and Tutorials</h2><br />
<ul><br />
<li>[http://blog.tupil.com/a-small-mashup-of-upcoming-and-lastfm-in-haskell/ A small mashup of Upcoming and Last.fm, in Haskell]</li><br />
<li>[http://hpaste.org/8521 A small example similar to above for retrieving and processing rss in a trivial fashion using Network.Curl and Text.XML.Light]</li><br />
</ul><br />
<br />
[[Category:Packages]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=21281Network.Curl2008-06-11T15:42:27Z<p>B7j0c: </p>
<hr />
<div><br />
<br />
This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.<br />
<br />
<h2>Trivial Use</h2><br />
<pre><br />
$ ghci<br />
Prelude> :m Network.Curl<br />
Prelude Network.Curl> let html = curlGetString "http://www.haskell.org/" []<br />
</pre><br />
<br />
<h2>External Examples and Tutorials</h2><br />
<ul><br />
<li>[http://blog.tupil.com/a-small-mashup-of-upcoming-and-lastfm-in-haskell/ A small mashup of Upcoming and Last.fm, in Haskell]</li><br />
</ul></div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=21280Network.Curl2008-06-11T15:41:22Z<p>B7j0c: </p>
<hr />
<div>== Network.Curl ==<br />
<br />
This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.<br />
<br />
<h2>Trivial Use</h2><br />
<pre><br />
$ ghci<br />
Prelude> :m Network.Curl<br />
Prelude Network.Curl> let html = curlGetString "http://www.haskell.org/" []<br />
</pre><br />
<br />
<h2>External Examples and Tutorials</h2><br />
<ul><br />
<li>[http://blog.tupil.com/a-small-mashup-of-upcoming-and-lastfm-in-haskell/ A small mashup of Upcoming and Last.fm, in Haskell]</li><br />
</ul></div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=21279Network.Curl2008-06-11T15:40:46Z<p>B7j0c: </p>
<hr />
<div>== Network.Curl ==<br />
<br />
This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.<br />
<br />
<h2>Trivial Use</h2><br />
<pre><br />
$ ghci<br />
Prelude> :m Network.Curl<br />
Prelude Network.Curl> let html = curlGetString "http://www.haskell.org/"<br />
</pre><br />
<br />
<h2>External Examples and Tutorials</h2><br />
<ul><br />
<li>[http://blog.tupil.com/a-small-mashup-of-upcoming-and-lastfm-in-haskell/ A small mashup of Upcoming and Last.fm, in Haskell]</li><br />
</ul></div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=21278Network.Curl2008-06-11T15:39:53Z<p>B7j0c: </p>
<hr />
<div>== Network.Curl ==<br />
<br />
This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.<br />
<br />
<h2>Trivial Use</h2><br />
<br />
<h2>External Examples and Tutorials</h2><br />
<ul><br />
<li>[http://blog.tupil.com/a-small-mashup-of-upcoming-and-lastfm-in-haskell/ A small mashup of Upcoming and Last.fm, in Haskell]</li><br />
</ul></div>B7j0chttps://wiki.haskell.org/index.php?title=Network.Curl&diff=20678Network.Curl2008-04-24T15:51:55Z<p>B7j0c: stub page for curl bindings</p>
<hr />
<div>== Network.Curl ==<br />
<br />
This page collections documentation and examples about the library<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl-1.3.2 Network.Curl], ([http://code.haskell.org/~dons/docs/curl/ docs]) a [http://curl.haxx.se/ curl] binding for Haskell,<br />
developed at Galois, Inc.</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18261Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:29:58Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre><br />
<br/><br />
<hr/><br />
[[Image:brad.png|center|200px]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive&diff=18260Xmonad/Config archive2008-01-12T07:28:39Z<p>B7j0c: </p>
<hr />
<div>{{xmonad}}<br />
<br />
==xmonad configuration examples==<br />
<br />
Configuration files (Config.hs for xmonad < 0.5, xmonad.hs for xmonad >= 0.5)<br />
<br />
For more screenshots see the [[Xmonad/Screenshots]] archive.<br />
<br />
;[[/Template Config.hs]] (0.5)<br />
:The default xmonad settings, in the form of a template, so you can easily edit and replace any values.<br />
<br />
;[[/Don's xmonad.hs]] (0.5)<br />
:[[/Don's Config.hs]] (0.4)<br />
:colours, use custom terminal, dynamicLogDzen<br />
[[Image:dons-config.png|center|200px]]<br />
<br />
;[[/Gwern's Config.hs]] (0.5)<br />
:[[/Gwern's Config.hs (0.4)]] (old)<br />
:Ratpoison-y keybindings; example usage of XSelection.<br />
<br />
;[[/twifkak's xmonad.hs]] (0.5)<br />
:[[/twifkak's Config.hs]] (0.4)<br />
:modMask = mod4Mask; noBorders tabbed layout; keybindings for dzen, rotview, swapworkspaces, windowbringer, and windownavigation; urgencyhook (only in darcs xmonad).<br />
<br />
;[[/nomeatas Config.hs]] (0.4)<br />
:modMaks = mod4Mask; gnome-stuff<br />
<br />
;[[/David Roundy's xmonad.hs]] (0.5)<br />
:Combo config for small screen + xclock. Requires the xmonad-library branch, so not for the faint of heart. This config also keeps mod=mod1, and therefore moves a number of key bindings to non-standard locations (my laptop has no spare modifier keys).<br />
[[Image:droundy-config.png|center|200px]]<br />
<br />
;[[/Brent Yorgey's xmonad.hs]] (0.5 darcs)<br />
:Only works with darcs xmonad. modMask = mod4Mask; DynamicLog, RotView, ViewPrev, WindowNavigation, ToggleLayouts (toggle full screen mode), UrgencyHook + dzen, FlexibleManipulate, a bunch of Prompts, Submap, Search, and a few others, with keybindings for all! (Warning: lots of non-standard keybindings. =)<br />
[[Image:byorgey-config.png|center|200px]]<br />
<br />
;[[/Robert Manea's xmonad.hs]] (0.5)<br />
:[[/Robert Manea's Config.hs and support scripts]] (0.4)<br />
:Customized DynamicLog and ShellPrompt, ManageDock, some efforts to make the colors of all components go together well<br />
0.4 screenshot: [[Image:rob-config.png|center|400px]]<br />
0.5 screenshot: [[Image:Xmonad_shellprompt_newconf.png|center|400px]]<br />
<br />
;[[/Eric Mertens' xmonad.hs]] (0.5)<br />
:[[/Eric Mertens's Config.hs]] (0.4)<br />
:Customized DynamicLog, ShellPrompt, TilePrime, Dual-head and an effort to make the statusbar similar to DWM.<br />
[[Image:glguy-config.jpg|center|400px]]<br />
<br />
;[[/vvv's xmonad.hs]] (0.5)<br />
:[[/vvv's Config.hs]] (0.4)<br />
:CustomKeys, CycleWS, {Shell,Ssh,Man}Prompt, Submap, DynamicWorkspaces, NoBorders, and ion-like status bar written in nonkosher Perl.<br />
[[Image:vvv-config.png|center|200px]]<br />
<br />
;[[/Andrea Rossato's xmonad.hs]] (0.5)<br />
:[[/arossato's Config.hs]] (0.4)<br />
:Tabbed, Xmobar with DynamicLog, (Shell|Ssh|Man)Prompt.<br />
[[Image:Arossato-config.png|center|200px]]<br />
<br />
;[[/Octoploid's xmonad.hs]] (0.5)<br />
:Xmobar with customized DynamicLog, RotView with custom keys, colors, terminal, golden ratio<br />
[[Image:Octoploid_conf.png|center|200px]]<br />
[[Image:Octoploid_conf2.png|center|200px]]<br />
<br />
;[[/Ray's xmonad.hs]] (0.5)<br />
:DynamicLog, custom manageHook, changed from default terminal, border colors, prompts, and layouts. Pseudo-Haskell dzen statusbar with greek letters for workspace names.<br />
[[Image:Ray-config.png|center|200px]]<br />
<br />
;[[/nattfodd's xmonad.hs]] (0.5)<br />
:DynamicLog, NoBorders, urgencyHook and French keyboard.<br />
[[Image:Nattfodd-scrot.png|center|200px]]<br />
<br />
;[[/deifl's xmonad.hs]] (0.5)<br />
:DynamicLog, WindowBringer, CopyWindow, ResizableTile, Tabbed layout. not default terminal, changed colors and some instances of dzen.<br />
Clean: [[Image:D_xmonad_clear.jpg|center|200px]]<br />
Populated: [[Image:D_xmonad_full.jpg|center|200px]]<br />
<br />
;[[/Xilon's xmonad.hs]] (0.5)<br />
:Simple and clean setup with dzen and a tray. Dzen with workspaces uses UrgencyHook for Urgent windows.<br />
[[Image:xilon-config.png|center|200px]]<br />
<br />
; [[/skorpan's xmonad.hs]] (0.5)<br />
: Basically slight modifications of rob's setup.<br />
[[Image:Skorpan.png|center|200px]]<br />
<br />
;[[/loupgaroublonds xmonad.hs]] (0.5)<br />
: mostly a stock config but with support for gnome and my cat<br />
[[Image:loupgaroublond-config.png|center|200px]]<br />
<br />
;[[/cce xmonad.hs]] (0.5)<br />
: alt+enter full screen, alt+hjkl to navigate, many remapped keys<br />
<br />
;[[/entropies xmonad.hs]] (0.5)<br />
: windows as meta key, fullscreen & noborders on keypress for client. custom keybindings. magnifier.<br />
[[Image:entropie-config.png|center|200px]]<br />
<br />
; [[/brad's xmonad.hs]] (0.5)<br />
: very basic, just some cosmetic and key-shortcut changes<br />
[[Image:brad.png|center|200px]]<br />
== Note on uploading ==<br />
<br />
To upload your config file, create some text on this page of the form:<br />
<br />
<nowiki>; [[/you Config.hs]]</nowiki><br />
<nowiki>: description of your setup</nowiki><br />
<br />
and save the page. This will create a new page under /you into which you<br />
can paste your Config.hs text. Wrap them in <nowiki><haskell></nowiki> and <nowiki></haskell></nowiki><br />
tags, to enable nice markup; add a nice category like <nowiki>[[Category:XMonad configuration]]</nowiki>, and upload. If you have an xmonad.hs for xmonad 0.5,<br />
upload that to<br />
<br />
<nowiki>; [[/you xmonad.hs]]</nowiki><br />
<br />
Images can be uploaded by clicking on the 'Upload file' link, and then<br />
referring to the uploaded image as, e.g.<br />
<br />
<nowiki>[[Image:you-config.png|center|200px]]</nowiki><br />
<br />
which will scale the image correctly for a thumbnail.<br />
<br />
[[Category:XMonad configuration]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18259Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:27:05Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre><br />
<br />
[[Image:brad.png|center|200px]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18258Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:25:42Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre><br />
<br />
[[Image:brad.png|center|200px]]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18257Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:25:05Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre><br />
<br />
[[Image:brad.png]]</div>B7j0chttps://wiki.haskell.org/index.php?title=File:Brad.png&diff=18256File:Brad.png2008-01-12T07:23:44Z<p>B7j0c: </p>
<hr />
<div></div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18255Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:23:20Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre><br />
<br />
[[Image:Example.jpg]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18254Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:20:49Z<p>B7j0c: </p>
<hr />
<div><pre><br />
import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]<br />
</pre></div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive/brad%27s_xmonad.hs&diff=18253Xmonad/Config archive/brad's xmonad.hs2008-01-12T07:20:10Z<p>B7j0c: brad's xmonad 0.5 config</p>
<hr />
<div>import XMonad <br />
import qualified XMonad.StackSet as W<br />
import qualified Data.Map as M<br />
<br />
-- hopefully it is obvious what changes i want to impose in xmonad:<br />
-- 1. no borders<br />
-- 2. urxvt is my terminal<br />
-- 3. mod+shift+w launches ff in worksapce 2<br />
-- 4. mod+shift+u launches my shell<br />
-- 5. mod+shift+l locks the screen<br />
-- thats it! thanks to all the posters on xmonad.org whose configs i copied!<br />
<br />
main :: IO ()<br />
main = xmonad $ defaultConfig<br />
{ borderWidth = 0<br />
, terminal = "urxvt -bg black -fg white -vb +sb"<br />
, workspaces = ["shell", "web"] ++ map show [3..9]<br />
, normalBorderColor = "#000000"<br />
, focusedBorderColor = "#000000"<br />
, keys = \c -> myKeys c `M.union` keys defaultConfig c<br />
, manageHook = manageHook defaultConfig <+> myManageHook<br />
}<br />
<br />
myKeys conf@(XConfig {modMask = modm}) = M.fromList $<br />
[<br />
((modm .|. shiftMask, xK_w), spawn "firefox"),<br />
((modm .|. shiftMask, xK_u), spawn "urxvt -fg white -bg black -vb +sb -fn \"xft:Liberation Mono:pixelsize=20\""),<br />
((modm .|. shiftMask, xK_l), spawn "xlock -mode blank")<br />
]<br />
<br />
myManageHook :: ManageHook<br />
myManageHook = composeAll [<br />
className =? "Firefox-bin" --> doF(W.shift "web")<br />
]</div>B7j0chttps://wiki.haskell.org/index.php?title=Xmonad/Config_archive&diff=18252Xmonad/Config archive2008-01-12T07:19:18Z<p>B7j0c: </p>
<hr />
<div>{{xmonad}}<br />
<br />
==xmonad configuration examples==<br />
<br />
Configuration files (Config.hs for xmonad < 0.5, xmonad.hs for xmonad >= 0.5)<br />
<br />
For more screenshots see the [[Xmonad/Screenshots]] archive.<br />
<br />
;[[/Template Config.hs]] (0.5)<br />
:The default xmonad settings, in the form of a template, so you can easily edit and replace any values.<br />
<br />
;[[/Don's xmonad.hs]] (0.5)<br />
:[[/Don's Config.hs]] (0.4)<br />
:colours, use custom terminal, dynamicLogDzen<br />
[[Image:dons-config.png|center|200px]]<br />
<br />
;[[/Gwern's Config.hs]] (0.5)<br />
:[[/Gwern's Config.hs (0.4)]] (old)<br />
:Ratpoison-y keybindings; example usage of XSelection.<br />
<br />
;[[/twifkak's xmonad.hs]] (0.5)<br />
:[[/twifkak's Config.hs]] (0.4)<br />
:modMask = mod4Mask; noBorders tabbed layout; keybindings for dzen, rotview, swapworkspaces, windowbringer, and windownavigation; urgencyhook (only in darcs xmonad).<br />
<br />
;[[/nomeatas Config.hs]] (0.4)<br />
:modMaks = mod4Mask; gnome-stuff<br />
<br />
;[[/David Roundy's xmonad.hs]] (0.5)<br />
:Combo config for small screen + xclock. Requires the xmonad-library branch, so not for the faint of heart. This config also keeps mod=mod1, and therefore moves a number of key bindings to non-standard locations (my laptop has no spare modifier keys).<br />
[[Image:droundy-config.png|center|200px]]<br />
<br />
;[[/Brent Yorgey's xmonad.hs]] (0.5 darcs)<br />
:Only works with darcs xmonad. modMask = mod4Mask; DynamicLog, RotView, ViewPrev, WindowNavigation, ToggleLayouts (toggle full screen mode), UrgencyHook + dzen, FlexibleManipulate, a bunch of Prompts, Submap, Search, and a few others, with keybindings for all! (Warning: lots of non-standard keybindings. =)<br />
[[Image:byorgey-config.png|center|200px]]<br />
<br />
;[[/Robert Manea's xmonad.hs]] (0.5)<br />
:[[/Robert Manea's Config.hs and support scripts]] (0.4)<br />
:Customized DynamicLog and ShellPrompt, ManageDock, some efforts to make the colors of all components go together well<br />
0.4 screenshot: [[Image:rob-config.png|center|400px]]<br />
0.5 screenshot: [[Image:Xmonad_shellprompt_newconf.png|center|400px]]<br />
<br />
;[[/Eric Mertens' xmonad.hs]] (0.5)<br />
:[[/Eric Mertens's Config.hs]] (0.4)<br />
:Customized DynamicLog, ShellPrompt, TilePrime, Dual-head and an effort to make the statusbar similar to DWM.<br />
[[Image:glguy-config.jpg|center|400px]]<br />
<br />
;[[/vvv's xmonad.hs]] (0.5)<br />
:[[/vvv's Config.hs]] (0.4)<br />
:CustomKeys, CycleWS, {Shell,Ssh,Man}Prompt, Submap, DynamicWorkspaces, NoBorders, and ion-like status bar written in nonkosher Perl.<br />
[[Image:vvv-config.png|center|200px]]<br />
<br />
;[[/Andrea Rossato's xmonad.hs]] (0.5)<br />
:[[/arossato's Config.hs]] (0.4)<br />
:Tabbed, Xmobar with DynamicLog, (Shell|Ssh|Man)Prompt.<br />
[[Image:Arossato-config.png|center|200px]]<br />
<br />
;[[/Octoploid's xmonad.hs]] (0.5)<br />
:Xmobar with customized DynamicLog, RotView with custom keys, colors, terminal, golden ratio<br />
[[Image:Octoploid_conf.png|center|200px]]<br />
[[Image:Octoploid_conf2.png|center|200px]]<br />
<br />
;[[/Ray's xmonad.hs]] (0.5)<br />
:DynamicLog, custom manageHook, changed from default terminal, border colors, prompts, and layouts. Pseudo-Haskell dzen statusbar with greek letters for workspace names.<br />
[[Image:Ray-config.png|center|200px]]<br />
<br />
;[[/nattfodd's xmonad.hs]] (0.5)<br />
:DynamicLog, NoBorders, urgencyHook and French keyboard.<br />
[[Image:Nattfodd-scrot.png|center|200px]]<br />
<br />
;[[/deifl's xmonad.hs]] (0.5)<br />
:DynamicLog, WindowBringer, CopyWindow, ResizableTile, Tabbed layout. not default terminal, changed colors and some instances of dzen.<br />
Clean: [[Image:D_xmonad_clear.jpg|center|200px]]<br />
Populated: [[Image:D_xmonad_full.jpg|center|200px]]<br />
<br />
;[[/Xilon's xmonad.hs]] (0.5)<br />
:Simple and clean setup with dzen and a tray. Dzen with workspaces uses UrgencyHook for Urgent windows.<br />
[[Image:xilon-config.png|center|200px]]<br />
<br />
; [[/skorpan's xmonad.hs]] (0.5)<br />
: Basically slight modifications of rob's setup.<br />
[[Image:Skorpan.png|center|200px]]<br />
<br />
;[[/loupgaroublonds xmonad.hs]] (0.5)<br />
: mostly a stock config but with support for gnome and my cat<br />
[[Image:loupgaroublond-config.png|center|200px]]<br />
<br />
;[[/cce xmonad.hs]] (0.5)<br />
: alt+enter full screen, alt+hjkl to navigate, many remapped keys<br />
<br />
;[[/entropies xmonad.hs]] (0.5)<br />
: windows as meta key, fullscreen & noborders on keypress for client. custom keybindings. magnifier.<br />
[[Image:entropie-config.png|center|200px]]<br />
<br />
; [[/brad's xmonad.hs]] (0.5)<br />
<br />
== Note on uploading ==<br />
<br />
To upload your config file, create some text on this page of the form:<br />
<br />
<nowiki>; [[/you Config.hs]]</nowiki><br />
<nowiki>: description of your setup</nowiki><br />
<br />
and save the page. This will create a new page under /you into which you<br />
can paste your Config.hs text. Wrap them in <nowiki><haskell></nowiki> and <nowiki></haskell></nowiki><br />
tags, to enable nice markup; add a nice category like <nowiki>[[Category:XMonad configuration]]</nowiki>, and upload. If you have an xmonad.hs for xmonad 0.5,<br />
upload that to<br />
<br />
<nowiki>; [[/you xmonad.hs]]</nowiki><br />
<br />
Images can be uploaded by clicking on the 'Upload file' link, and then<br />
referring to the uploaded image as, e.g.<br />
<br />
<nowiki>[[Image:you-config.png|center|200px]]</nowiki><br />
<br />
which will scale the image correctly for a thumbnail.<br />
<br />
[[Category:XMonad configuration]]</div>B7j0chttps://wiki.haskell.org/index.php?title=User:B7j0c&diff=14670User:B7j0c2007-07-25T03:31:50Z<p>B7j0c: </p>
<hr />
<div>A lurker on haskell-cafe, #haskell and the author of Network.HTTP.Simple and Finance.Quote.Yahoo.</div>B7j0chttps://wiki.haskell.org/index.php?title=User:B7j0c&diff=14669User:B7j0c2007-07-25T03:31:36Z<p>B7j0c: </p>
<hr />
<div>A lurker on haskell-cafe, #haskell and the author of Network.HttP.Simple and Finance.Quote.Yahoo.</div>B7j0chttps://wiki.haskell.org/index.php?title=Haskell_Cafe_migration&diff=14668Haskell Cafe migration2007-07-25T03:28:34Z<p>B7j0c: added brad clawsie to permissive license</p>
<hr />
<div>Often people post wonderful material to the mailing lists, hpaste.org or<br />
on #haskell. This can later be hard to find. The goal of this page is to<br />
collect a list of people who are happy for their contributions to the<br />
Haskell community, in any media, to be added directly to the Haskell wiki.<br />
<br />
If you are happy for your contributions (both new and old posts) on <br />
''any media that are part of the Haskell community'', including:<br />
<br />
* [[Mailing_lists|The mailing lists]] (haskell-cafe@, libraries@ and others)<br />
* [[IRC_channel|The IRC channel]]<br />
* [http://hpaste.org/ The Haskell Paste Bin]: hpaste.org<br />
* [[HaWiki_migration|The Old Haskell Wiki]]<br />
* And the new wiki.<br />
<br />
that ''are not specifically licensed'' to be treated as having been<br />
released under a [[HaskellWiki:Copyrights|Simple Permissive License]].<br />
please add your name to this list, so that others may move your<br />
contributions around haskell.org without fear.<br />
<br />
''Contributions will be licensed specifically under a<br />
[[HaskellWiki:Copyrights|Simple Permissive License]]''.<br />
<br />
* Andrew Bromage (aka Pseudonym)<br />
* Arthur van Leeuwen (aka earthy)<br />
* Bernie Pope<br />
* [[User:b7j0c | Brad Clawsie]]<br />
* Brandon Allbery<br />
* [[User:BrettGiles | Brett Giles]]<br />
* Bulat Ziganshin<br />
* Cale Gibbard<br />
* Chris Smith (cdsmith; blog also fair game)<br />
* Conor McBride<br />
* Conrad Parker<br />
* Dan Doel<br />
* Dan Piponi (aka sigfpe)<br />
* Derek Elkins<br />
* Dominic Steinitz<br />
* Don Stewart<br />
* Eric Kow (kowey; blog too)<br />
* Henk-Jan van Tuyl<br />
* Ian Lynagh (Igloo)<br />
* Jan-Willem Maessen<br />
* Jonathan Cast<br />
* Neil Mitchell (ndm)<br />
* Richard Kelsall<br />
* Richard O'Keefe<br />
* Samuel Bronson (SamB)<br />
* ShaeErisson<br />
* Stefan O'Rear<br />
* Thorkil Naur<br />
* Tim Chevalier (aka Kirsten)<br />
* Tom Conway<br />
<br />
[[Category:Community]]</div>B7j0chttps://wiki.haskell.org/index.php?title=HXT&diff=11935HXT2007-03-13T02:40:44Z<p>B7j0c: changed "maipulation" to "manipulation", typo fix</p>
<hr />
<div>[[Category:Tools]] [[Category:Tutorials]]<br />
<br />
== A gentle introduction to the Haskell XML Toolbox ==<br />
<br />
The [http://www.fh-wedel.de/~si/HXmlToolbox/index.html Haskell XML Toolbox (HXT)] is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language, consisting of a set of combinators, for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace aware XML-Parser that supports almost fully the XML 1.0 Standard. Extensions are a validator for RelaxNG and an XPath evaluator.<br />
<br />
__TOC__<br />
<br />
== Background ==<br />
<br />
The Haskell XML Toolbox bases on the ideas of [http://www.cs.york.ac.uk/fp/HaXml/ HaXml] and [http://www.flightlab.com/~joe/hxml/ HXML] but introduces a more general approach for processing XML with Haskell. HXT uses a generic data model for representing XML documents, including the DTD subset, entity references, CData parts and processing instructions. This data model makes it possible to use tree transformation functions as a uniform design of XML processing steps from parsing, DTD processing, entity processing, validation, namespace propagation, content processing and output.<br />
<br />
== Resources ==<br />
<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/index.html HXT Home] :<br />
; [http://www.fh-wedel.de/~si/HXmlToolbox/HXT-7.0.tar.gz HXT-7.0.tar.gz] : lastest release<br />
; [http://darcs.fh-wedel.de/hxt/ darcs.fh-wedel.de/hxt] : darcs repository with head revision of HXT<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc_arrow/ Arrow API] : Haddock documentation of head revision with links to source files<br />
; [http://darcs.fh-wedel.de/hxt/doc/hdoc/ Complete API] : Haddock documentation with arrows and old API based on filters<br />
<br />
== The basic concepts ==<br />
<br />
=== The basic data structures ===<br />
<br />
Processing of XML is a task of processing tree structures. This is can be done in Haskell in a very elegant way by defining an appropriate tree data type, a Haskell DOM (document object model) structure. The tree structure in HXT is a rose tree with a special XNode data type for storing the XML node information.<br />
<br />
The generally useful tree structure (NTree) is separated from the node type (XNode). This allows for reusing the tree structure and the tree traversal and manipulation functions in other applications.<br />
<br />
<haskell><br />
type NTree a = NTree a [NTree a] -- rose tree<br />
<br />
data XNode = XText String -- plain text node<br />
| ...<br />
| XTag QName XmlTrees -- element name and list of attributes<br />
| XAttr QName -- attribute name<br />
| ...<br />
<br />
type QName = ... -- qualified name<br />
<br />
type XmlTree = NTree XNode<br />
<br />
type XmlTrees = [XmlTree]<br />
</haskell><br />
<br />
=== The concept of filters ===<br />
<br />
Selecting, transforming and generating trees often requires routines, which compute not only a single result tree, but a (possibly empty) list of (sub-)trees. This leads to the idea of XML filters like in HaXml. Filters are functions, which take an XML tree as input and compute a list of result trees.<br />
<br />
<haskell><br />
type XmlFilter = XmlTree -> [XmlTree]<br />
</haskell><br />
<br />
More generally we can define a filter as<br />
<br />
<haskell><br />
type Filter a b = a -> [b]<br />
</haskell><br />
<br />
We will do this abstraction later, when introducing arrows. Many of the functions in the following motivating examples can be generalised this way. But for getting the idea, the <hask>XmlFilter</hask> is sufficient.<br />
<br />
The filter functions are used so frequently, that the idea of defining a domain specific language with filters as the basic processing units comes up. In such a DSL the basic filters are predicates, selectors, constructors and transformers, all working on the HXT DOM tree structure. For a DSL it becomes neccessary to define an appropriate set of combinators for building more complex functions from simpler ones. Of course filter composition, like (.) becomes one of the most frequently used combinators. there are more complex filters for traversal of a whole tree and selection or transformation of several nodes. We will see a few first examples in the following part.<br />
<br />
The first task is to build filters from pure functions, to define a lift operator. Pure functions are lifted to filters in the following way:<br />
<br />
Predicates are lifted by mapping False to the empty list and True to the single element list, containing the input tree.<br />
<br />
<haskell><br />
p :: XmlTree -> Bool -- pure function<br />
p t = ...<br />
<br />
pf :: XmlTree -> [XmlTree] -- or XmlFilter<br />
pf t<br />
| p t = [t]<br />
| otherwise = []<br />
</haskell><br />
<br />
The combinator for this type of lifting is called <hask>isA</hask>, it works on any type and is defined as<br />
<br />
<haskell><br />
isA :: (a -> Bool) -> (a -> [a])<br />
isA p x<br />
| p x = [x]<br />
| otherwise = []<br />
</haskell><br />
<br />
A predicate for filtering text nodes looks like this<br />
<br />
<haskell><br />
isText :: XmlFilter -- XmlTree -> [XmlTrees]<br />
isText t@(NTree (XText _) _) = [t]<br />
isText _ = []<br />
</haskell><br />
<br />
Transformers, function that map a tree into another tree, are lifted in a trivial way:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t = exp(t)<br />
<br />
ff :: XmlTree -> [XmlTree]<br />
ff t = [exp(t)]<br />
</haskell><br />
<br />
This basic function is called <hask>arr</hask>, it comes from the Control.Arrow module of the basic library package of ghc.<br />
<br />
Partial functions, functions that can't always compute a result, are usually lifted to totally defined filters:<br />
<br />
<haskell><br />
f :: XmlTree -> XmlTree<br />
f t<br />
| p t = expr(t)<br />
| otherwise = error "f not defined"<br />
<br />
ff :: XmlFilter<br />
ff t<br />
| p t = [expr(t)]<br />
| otherwise = []<br />
</haskell><br />
<br />
This is a rather comfortable situation, with these filters we don't have to deal with illegal argument errors. Illegal arguments are just mapped to the empty list.<br />
<br />
When processing trees, there's often the case, that no, exactly one, or more than one result is possible. These functions, returning a set of results are often a bit imprecisely called ''nondeterministic'' functions. These functions, e.g. selecting all children of a node or all grandchildren, are exactly our filters. In this context lists instead of sets of values are the appropriate result type, because the ordering in XML is important and duplicates are possible.<br />
<br />
Working with filters is rather similar to working with binary relations, and working with relations is rather natural and comfortable, database people do know this very well.<br />
<br />
Two first examples for working with ''nondeterministic'' functions are selecting the children and the grandchildren of an XmlTree which can be implemented by<br />
<br />
<haskell><br />
getChildren :: XmlFilter<br />
getChildren (NTree n cs)<br />
= cs<br />
<br />
getGrandChildren :: XmlFilter<br />
getGrandChildren (NTree n cs)<br />
= concat [ getChildren c | c <- cs ]<br />
</haskell><br />
<br />
=== Filter combinators ===<br />
<br />
Composition of filters (like function composition) is the most important combinator. We will use the infix operator <hask>(>>>)</hask> for filter composition and reverse the arguments, so we can read composition sequences from left to right, like with pipes in Unix. Composition is defined as follows:<br />
<br />
<haskell><br />
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f >>> g) t = concat [g t' | t' <- f t]<br />
</haskell><br />
<br />
This definition corresponds 1-1 to the composition of binary relations. With help of the <hask>(>>>)</hask> operator the definition of <hask>getGrandChildren</hask> becomes rather simple:<br />
<br />
<haskell><br />
getGrandChildren :: XmlFilter<br />
getGrandChildren = getChildren >>> getChildren<br />
</haskell><br />
<br />
Selecting all text nodes of the children of an element can also be formulated very easily with the help of <hask>(>>>)</hask><br />
<br />
<haskell><br />
getTextChildren :: XmlFilter<br />
getTextChildren = getChildren >>> isText<br />
</haskell><br />
<br />
In case of predicate filter the <hask>(>>>)</hask> serves as a logical and operator, or from the relational view as an intersection operator: <hask>isA p1 >>> isA p2</hask> selects all values for which p1 and p2 both hold.<br />
<br />
The dual operator to <hask>(>>>)</hask> is the locical or, (thinking in sets: The union operator). For this we define a sum operator <hask>(<+>)</hask>. The sum of two filters is defined as follows:<br />
<br />
<haskell><br />
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter<br />
<br />
(f <+> g) t = f t ++ g t<br />
</haskell><br />
<br />
Example: <hask>isA p1 <+> isA p2</hask> is the locical or for filter.<br />
<br />
Combining elementary filters with (>>>) and (<+>) leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulated with:<br />
<br />
<haskell><br />
getTextChildren2 :: XmlFilter<br />
getTextChildren2 = getChildren >>> ( isText <+> ( getChildren >>> isText ) )<br />
</haskell><br />
<br />
'''Exercise:''' Are these filters equivalent or what's the difference between the two filters?<br />
<br />
<haskell><br />
getChildren >>> ( isText <+> ( getChildren >>> isText ) )<br />
<br />
( getChildren >>> isText ) <+> ( getChildren >>> getChildren >>> isText )<br />
</haskell><br />
<br />
Of course we need choice combinators. The first idea is an if-then-else filter, <br />
built up from three simpler filters. But often it's easier and more elegant to work with simpler binary combinators for choice. So we will introduce the simpler ones first.<br />
<br />
One of these choice combinators is called <hask>orElse</hask> and is defined as<br />
follows:<br />
<br />
<haskell><br />
orElse :: XmlFilter -> XmlFilter -> XmlFilter<br />
orElse f g t<br />
| null res1 = g t<br />
| otherwise = res1<br />
where<br />
res1 = f t<br />
</haskell><br />
<br />
The meaning is the following: If f computes a none empty list as result, f succeeds and this list is the result, else g is applied to the input and this yields the result. There are two other simple choice combinators usually written in infix notation, <hask> g `guards` f</hask> and <hask>f `when` g</hask>:<br />
<br />
<haskell><br />
guards :: XmlFilter -> XmlFilter -> XmlFilter<br />
guards g f t<br />
| null (g t) = []<br />
| otherwise = f t<br />
<br />
when :: XmlFilter -> XmlFilter -> XmlFilter<br />
when f g t<br />
| null (g t) = [t]<br />
| otherwise = f t<br />
</haskell><br />
<br />
These choice operators become useful when transforming and manipulation trees.<br />
<br />
=== Tree traversal filter ===<br />
<br />
A very basic operation on tree structures is the traversal of all nodes and the selection and/or transformation of nodes. Theses traversal filters serve as control structures for processing whole trees. They correspond to the map and fold combinators for lists.<br />
<br />
The simplest traversal filter does a top down search of all nodes with a special feature. This filter, called <hask>deep</hask>, is defined as follows:<br />
<br />
<haskell><br />
deep :: XmlFilter -> XmlFilter<br />
deep f = f `orElse` (getChildren >>> deep f)<br />
</haskell><br />
<br />
When a predicate filter is applied to <hask>deep</hask>, a top down search is done and all subtrees satisfying the predicate are collected. The descent into the tree stops, when a subtree is found because of the use of <hask>orElse</hask>.<br />
<br />
'''Example:''' Selecting all plain text nodes of a document can be formulated with:<br />
<br />
<haskell><br />
deep isText<br />
</haskell><br />
<br />
'''Example:''' Selecting all "top level" tables in a HTML documents looks like<br />
this:<br />
<br />
<haskell><br />
deep (isElem >>> hasName "table")<br />
</haskell><br />
<br />
A variant of <hask>deep</hask>, called <hask>multi</hask>, performs a complete search, where the tree traversal does not stop, when a node is found.<br />
<br />
<haskell><br />
multi :: XmlFilter -> XmlFilter<br />
multi f = f <+> (getChildren >>> multi f)<br />
</haskell><br />
<br />
'''Example:''' Selecting all tables in a HTML document, even nested ones, <hask>multi</hask> has to be used instead of <hask>deep</hask>:<br />
<br />
<hask>multi (isElem >>> hasName "table")</hask><br />
<br />
=== Arrows ===<br />
<br />
We've already seen, that the filters <hask>a -> [b]</hask> are a very<br />
powerful and sometimes a more elgant way to process XML than pure<br />
function. This is the good news. The bad news is, that filter are not<br />
general enough. Of course we sometimes want to do some I/O and we want<br />
to stay in the filter level. So we need something like<br />
<br />
<haskell><br />
type XmlIOFilter = XmlTree -> IO [XmlTree]<br />
</haskell><br />
<br />
for working in the IO monad.<br />
<br />
Sometimes it's apropriate to thread some state through the computation<br />
like in state monads. This leads to a type like<br />
<br />
<haskell><br />
type XmlStateFilter state = state -> XmlTree -> (state, [XmlTree])<br />
</haskell><br />
<br />
And in real world applications we need both extenstions at the same<br />
time. Of course I/O is neccessary but usually there are also some<br />
global options and variables for controlling the computations. In HXT,<br />
for instance there are variables for controlling trace output, options<br />
for setting the default encoding scheme for input data and a base URI<br />
for accessing documents, which are addressed in a content or in a DTD<br />
part by relative URIs. So we need something like<br />
<br />
<haskell><br />
type XmlIOStateFilter state = state -> XmlTree -> IO (state, [XmlTree])<br />
</haskell><br />
<br />
We want to work with all four filter variants, and in the future<br />
perhaps with even more general filters, but of course not with four<br />
sets of filter names, e.g. <hask>deep, deepST, deepIO, deepIOST</hask>.<br />
<br />
This is the point where <hask>newtype</hask>s and <hask>class</hask>es<br />
come in. Classes are needed for overloading names and<br />
<hask>newtype</hask>s are needed to declare instances. Further the<br />
restriction of <hask>XmlTree</hask> as argument and result type is<br />
not neccessary and hinders reuse in many cases.<br />
<br />
A filter discussed above has all features of an arrow. Arrows are<br />
introduced for generalising the concept of functions and function<br />
combination to more general kinds of computation than pure functions.<br />
<br />
A basic set of combinators for arrows is defined in the classes in the<br />
<hask>Control.Arrow</hask> module, containing the above mentioned <hask>(>>>), (<+>), arr</hask>.<br />
<br />
In HXT the additional classes for filters working with lists as result type are<br />
defined in <hask>Control.Arrow.ArrowList</hask>. The choice operators are<br />
in <hask>Control.Arrow.ArrowIf</hask>, tree filters, like <hask>getChildren, deep, multi, ...</hask> in<br />
<hask>Control.Arrow.ArrowTree</hask> and the elementary XML specific<br />
filters in <hask>Text.XML.HXT.XmlArrow</hask>.<br />
<br />
In HXT there are four types instanciated with these classes for<br />
pure list arrows, list arrows with a state, list arrows with IO<br />
and list arrows with a state and IO.<br />
<br />
<haskell><br />
newtype LA a b = LA { runLA :: (a -> [b]) }<br />
<br />
newtype SLA s a b = SLA { runSLA :: (s -> a -> (s, [b])) }<br />
<br />
newtype IOLA a b = IOLA { runIOLA :: (a -> IO [b]) }<br />
<br />
newtype IOSLA s a b = IOSLA { runIOSLA :: (s -> a -> IO (s, [b])) }<br />
</haskell><br />
<br />
The first one and the last one are those used most frequently in the<br />
toolbox, and of course there are lifting functions for converting the<br />
special arrows into the more general ones.<br />
<br />
Don't worry about all these conceptional details. Let's have a look into some<br />
''Hello world'' examples.<br />
<br />
== Getting started: Hello world examples ==<br />
<br />
=== copyXML ===<br />
<br />
The first complete example is a program for<br />
copying an XML document<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
import System.Environment<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
[src, dst] <- getArgs<br />
runX ( readDocument [(a_validate, v_0)] src<br />
>>><br />
writeDocument [] dst<br />
)<br />
return ()<br />
</haskell><br />
<br />
The interesting part of this example is<br />
the call of <hask>runX</hask>. <hask>runX</hask> executes an<br />
arrow. This arrow is one of the more powerful list arrows with IO and<br />
a HXT system state.<br />
<br />
The arrow itself is a composition of <hask>readDocument</hask> and<br />
<hask>writeDocument</hask>.<br />
<hask>readDocument</hask> is an arrow for reading, DTD processing and<br />
validation of documents. Its behaviour can be controlled by a list of<br />
options. Here we turn off the validation step. The <hask>src</hask>, a file<br />
name or an URI is read and parsed and a document tree is built. This<br />
tree is ''piped'' into the output arrow. This one also is<br />
controlled by a set of options. Here all the defaults are used.<br />
<hask>writeDocument</hask> converts the tree into a string and writes<br />
it to the <hask>dst</hask>.<br />
<br />
We've omitted here the boring stuff of option parsing and error<br />
handling.<br />
<br />
Compilation and a test run looks like this:<br />
<br />
<pre><br />
hobel > ghc -o copyXml -package hxt CopyXML.hs<br />
hobel > cat hello.xml<br />
<hello>world</hello><br />
hobel > copyXml hello.xml -<br />
<?xml version="1.0" encoding="UTF-8"?><br />
<hello>world</hello><br />
hobel ><br />
</pre><br />
<br />
The mini XML document in file <tt>hello.xml</tt> is read and<br />
a document tree is built. Then this tree is converted into a string<br />
and written to standard output (filename: <tt>-</tt>). It is decorated<br />
with an XML declaration containing the version and the output<br />
encoding.<br />
<br />
For processing HTML documents there is a HTML parser, which tries to<br />
parse and interprete rather anything as HTML. The HTML parser can be<br />
selected by calling<br />
<br />
<hask>readDocument [(a_parse_html, v_1), ...]</hask><br />
<br />
with the apropriate option.<br />
<br />
=== Pattern for a main program ===<br />
<br />
A more realistic pattern for a simple Unix filter like program has<br />
the following structure:<br />
<br />
<haskell><br />
module Main<br />
where<br />
<br />
import Text.XML.HXT.Arrow<br />
<br />
import System.IO<br />
import System.Environment<br />
import System.Console.GetOpt<br />
import System.Exit<br />
<br />
main :: IO ()<br />
main<br />
= do<br />
argv <- getArgs<br />
(al, src, dst) <- cmdlineOpts argv<br />
[rc] <- runX (application al src dst)<br />
if rc >= c_err<br />
then exitWith (ExitFailure (0-1))<br />
else exitWith ExitSuccess<br />
<br />
-- | the dummy for the boring stuff of option evaluation,<br />
-- usually done with 'System.Console.GetOpt'<br />
<br />
cmdlineOpts :: [String] -> IO (Attributes, String, String)<br />
cmdlineOpts argv<br />
= return ([(a_validate, v_0)], argv!!0, argv!!1)<br />
<br />
-- | the main arrow<br />
<br />
application :: Attributes -> String -> String -> IOSArrow b Int<br />
application al src dst<br />
= readDocument al src<br />
>>><br />
processChildren (processDocumentRootElement `when` isElem) -- (1)<br />
>>><br />
writeDocument al dst<br />
>>><br />
getErrStatus<br />
<br />
<br />
-- | the dummy for the real processing: the identity filter<br />
<br />
processDocumentRootElement :: IOSArrow XmlTree XmlTree<br />
processDocumentRootElement<br />
= this -- substitute this by the real application<br />
</haskell><br />
<br />
This program has the same functionality as our first example,<br />
but it separates the arrow from the boring option evaluation and<br />
return code computation.<br />
<br />
The interesing line is (1).<br />
<hask>readDocument</hask> generates a tree structure with a so called extra<br />
root node. This root node is a node above the XML document root<br />
element. The node above the XML document root element is neccessary<br />
because of possible other elements on the same tree level as the XML<br />
root, for instance comments, processing instructions or whitespace.<br />
<br />
Furthermore the artificial root node serves for storing meta<br />
information about the document in the attribute list, like the<br />
document name, the encoding scheme, the HTTP transfer headers and<br />
other information.<br />
<br />
To process the real XML root element, we have to take the children of<br />
the root node, select the XML root element and process this, but<br />
remain all other children unchanged. This is done with<br />
<hask>processChildren</hask> and the <hask>when</hask> choice<br />
operator. <hask>processChildren</hask> applies a filter elementwise to<br />
all children of a node. All results form processing the list of children from<br />
the result node.<br />
<br />
The structure of internal document tree can be made visible<br />
e.g. by adding the option pair <hask>(a_show_tree, v_1)</hask> to the<br />
<hask>writeDocument</hask> arrow. This will emit the tree in a readable<br />
text representation instead of the real document.<br />
<br />
In the next section we will give examples for the<br />
<hask>processDocumentRootElement</hask> arrow.<br />
<br />
== Selection examples ==<br />
<br />
=== Selecting text from an HTML document ===<br />
<br />
Selecting all the plain text of an XML/HTML document<br />
can be formulated with<br />
<br />
<haskell><br />
selectAllText :: ArrowXml a => a XmlTree XmlTree<br />
selectAllText<br />
= deep isText<br />
</haskell><br />
<br />
<hask>deep</hask> traverses the whole tree, stops the traversal when<br />
a node is a text node (<hask>isText</hask>) and returns all the text nodes.<br />
There are two other traversal operators <hask>deepest</hask> and <hask>multi</hask>,<br />
In this case, where the selected nodes are all leave, these would give the same result.<br />
<br />
=== Selecting text and ALT attribute values ===<br />
<br />
Let's take a bit more complex tast: We want to select all text, but also the values of the <tt>alt</tt> attributes<br />
of image tags.<br />
<br />
<haskell><br />
selectAllTextAndAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndAltValues<br />
= deep<br />
( isText -- (1)<br />
<+><br />
( isElem >>> hasName "img" -- (2)<br />
>>><br />
getAttrValue "alt" -- (3)<br />
>>><br />
mkText -- (4)<br />
)<br />
)<br />
</haskell><br />
<br />
The whole tree is searched for text nodes (1) and for image elements (2), from the image elements<br />
the alt attribute values are selected as plain text (3), this text is transformed into a text node (4).<br />
<br />
=== Selecting text and ALT attributes values (2) ===<br />
<br />
Let's refine the above filter one step further. The text from the alt attributes shall be marked in the output<br />
by surrounding double square brackets. Empty alt values shall be ignored.<br />
<br />
<haskell><br />
selectAllTextAndRealAltValues :: ArrowXml a => a XmlTree XmlTree<br />
selectAllTextAndRealAltValues<br />
= deep<br />
( isText<br />
<+><br />
( isElem >>> hasName "img"<br />
>>><br />
getAttrValue "alt"<br />
>>><br />
isA significant -- (1)<br />
>>><br />
arr addBrackets -- (2)<br />
>>><br />
mkText<br />
)<br />
)<br />
where<br />
significant :: String -> Bool<br />
significant = not . all (`elem` " \n\r\t")<br />
<br />
addBrackets :: String -> String<br />
addBrackets s<br />
= " [[ " ++ s ++ " ]] "<br />
</haskell><br />
<br />
This example shows two combinators for building arrows from pure functions.<br />
The first one <hask>isA</hask> removes all empty or whitespace values from alt attributes (1),<br />
the other <hask>arr</hask> lifts the editing function to the arrow level (2).<br />
<br />
== Document construction examples ==<br />
<br />
=== The ''Hello World'' document ===<br />
<br />
The first document, of course, is a ''Hello World'' document:<br />
<br />
<haskell><br />
helloWorld :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld<br />
= mkelem "html" [] -- (1)<br />
[ mkelem "head" []<br />
[ mkelem "title" []<br />
[ txt "Hello World" ] -- (2)<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ] -- (3)<br />
[ mkelem "h1" []<br />
[ txt "Hello World" ] -- (4)<br />
]<br />
]<br />
</haskell><br />
<br />
The main arrows for document construction are <hask>mkelem</hask><br />
and it's variants (<hask>selem, aelem, eelem</hask>) for element creation, <hask>attr</hask> and <hask>sattr</hask> for attributes and <hask>mktext</hask><br />
and <hask>txt</hask> for text nodes.<br />
<br />
<hask>mkelem</hask> takes three arguments, the element name (or tag name),<br />
a list of arrows for the construction of attributes, not empty in (3),<br />
and a list of arrows for the contents. Text content is generated in (2) and (4).<br />
<br />
When <hask>writeDocument</hask> is called with the indent option<br />
(<hask>(a_indent, v_1)</hask>) the following output is generated<br />
(if the indent option is not given, the whole document would appears on a<br />
single line):<br />
<br />
<pre><br />
<?xml version="1.0" encoding="UTF-8"?><br />
<html><br />
<head><br />
<title>Hello World</title><br />
</head><br />
<body class="haskell"><br />
<h1>Hello World</h1><br />
</body><br />
</html><br />
</pre><br />
<br />
The code can be shortened a bit by using some of the<br />
convenient functions:<br />
<br />
<haskell><br />
helloWorld2 :: ArrowXml a => a XmlTree XmlTree<br />
helloWorld2<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Hello World" ]<br />
]<br />
, mkelem "body"<br />
[ sattr "class" "haskell" ]<br />
[ selem "h1"<br />
[ txt "Hello World" ]<br />
]<br />
]<br />
</haskell><br />
<br />
In the above two examples the arrow input is totally ignored, because<br />
of the use of the constant arrow <hask>txt "..."</hask>.<br />
<br />
=== A page about all images within a HTML page ===<br />
<br />
A bit more interesting task is the construction of a page<br />
containg a table of all images within a page inclusive image URLs, geometry and ALT attributes.<br />
<br />
The program for this has a frame similar to the <hask>helloWorld</hask> program,<br />
but the rows of the table must be filled in from the input document.<br />
In the first step we will generate a table with a single column containing<br />
the URL of the image.<br />
<br />
<haskell><br />
imageTable :: ArrowXml a => a XmlTree XmlTree<br />
imageTable<br />
= selem "html"<br />
[ selem "head"<br />
[ selem "title"<br />
[ txt "Images in Page" ]<br />
]<br />
, selem "body"<br />
[ selem "h1"<br />
[ txt "Images in Page" ]<br />
, selem "table"<br />
[ collectImages -- (1)<br />
>>><br />
genTableRows -- (2)<br />
]<br />
]<br />
]<br />
where<br />
collectImages -- (1)<br />
= deep ( isElem<br />
>>><br />
hasName "img"<br />
)<br />
genTableRows -- (2)<br />
= selem "tr"<br />
[ selem "td"<br />
[ getAttrValue "src" >>> mkText ]<br />
]<br />
</haskell><br />
<br />
With (1) the image elements are collected, and with (2)<br />
the HTML code for an image element is built.<br />
<br />
Applied to <tt>http://www.haskell.org/</tt> we get the following result<br />
(at the time writing this page):<br />
<br />
<pre><br />
<html><br />
<head><br />
<title>Images in Page</title><br />
</head><br />
<body><br />
<h1>Images in Page</h1><br />
<table><br />
<tr><br />
<td>/haskellwiki_logo.png</td><br />
</tr><br />
<tr><br />
<td>/sitewiki/images/1/10/Haskelllogo-small.jpg</td><br />
</tr><br />
<tr><br />
<td>/haskellwiki_logo_small.png</td><br />
</tr><br />
</table><br />
</body><br />
</html><br />
</pre><br />
<br />
When generating HTML, often there are constant parts within the page,<br />
in the example e.g. the page header. It's possible to write these<br />
parts as a string containing plain HTML and then read this with<br />
a simple XML contents parser called <hask>xread</hask>.<br />
<br />
The example above could then be rewritten as<br />
<br />
<haskell><br />
imageTable<br />
= selem "html"<br />
[ pageHeader<br />
, ...<br />
]<br />
where<br />
pageHeader<br />
= constA "<head><title>Images in Page</title></head>"<br />
>>><br />
xread<br />
...<br />
</haskell><br />
<br />
<hask>xread</hask> is a very primitive arrow. It does not run in the<br />
IO monad, so it can be used in any context, but therefore the error handling<br />
is very limited. <hask>xread</hask> parses an XML element content.<br />
<br />
=== A page about all images within a HTML page: 1. Refinement ===<br />
<br />
The next refinement step is the extension of the table such that<br />
it contains four columns, one for the image itself, one for the URL,<br />
the geometry and the ALT text. The extended <hask>getTableRows</hask><br />
has the following form:<br />
<br />
<haskell><br />
genTableRows<br />
= selem "tr"<br />
[ selem "td" -- (1)<br />
[ this -- (1.1)<br />
]<br />
, selem "td" -- (2)<br />
[ getAttrValue "src"<br />
>>><br />
mkText<br />
>>><br />
mkelem "a" -- (2.1)<br />
[ attr "href" this ]<br />
[ this ]<br />
]<br />
, selem "td" -- (3)<br />
[ ( getAttrValue "width"<br />
&&& -- (3.1)<br />
getAttrValue "height"<br />
)<br />
>>><br />
arr2 geometry -- (3.2)<br />
>>><br />
mkText<br />
]<br />
, selem "td" -- (4)<br />
[ getAttrValue "alt"<br />
>>><br />
mkText<br />
]<br />
]<br />
where<br />
geometry :: String -> String -> String<br />
geometry "" ""<br />
= ""<br />
geometry w h<br />
= w ++ "x" ++ h<br />
</haskell><br />
<br />
In (1) the identity arrow <hask>this</hask> is used for<br />
inserting the whole image element (<hask>this</hask> value) into the first column.<br />
(2) is the column from the previous example but the URL has been made active<br />
by embedding the URL in an A-element (2.1). In (3) there are two<br />
new combinators, <hask>(&&&)</hask> (3.1) is an arrow for applying two<br />
arrows to the same input and combine the results into a pair. <hask>arr2</hask><br />
works like <hask>arr</hask> but it lifts a binary function into an arrow<br />
accepting a pair of values. <hask>arr2 f</hask> is a shortcut for<br />
<hask>arr (uncurry f)</hask>. So width and height are combined into an X11 like<br />
geometry spec. (4) adds the ALT-text.<br />
<br />
=== A page about all images within a HTML page: 2. Refinement ===<br />
<br />
The generated HTML page is not yet very useful, because it usually<br />
contains relativ HREFs to the images, so the links do not work.<br />
We have to transform the SRC attribute values into absolute URLs.<br />
This can be done with the following code:<br />
<br />
<haskell><br />
imageTable2 :: IOStateArrow s XmlTree XmlTree<br />
imageTable2<br />
= ...<br />
...<br />
, selem "table"<br />
[ collectImages<br />
>>><br />
mkAbsImageRef -- (1)<br />
>>><br />
genTableRows<br />
]<br />
...<br />
<br />
mkAbsImageRef :: IOStateArrow s XmlTree XmlTree -- (1)<br />
mkAbsImageRef<br />
= processAttrl ( mkAbsRef -- (2)<br />
`when`<br />
hasName "src" -- (3)<br />
)<br />
where<br />
mkAbsRef -- (4)<br />
= replaceChildren<br />
( xshow getChildren -- (5)<br />
>>><br />
( mkAbsURI `orElse` this ) -- (6)<br />
>>><br />
mkText -- (7)<br />
)<br />
</haskell><br />
<br />
The <hask>imageTable2</hask> is extended by an arrow <hask>mkAbsImageRef</hask><br />
(1). This arrow uses the global system state of HXT, in which the base URL<br />
of a document is stored. For editing the SRC attribute value, the attribute list<br />
of the image elements is processed with <hask>processAttrl</hask>.<br />
With the <hask>`when` hasName "src"</hask> only SRC attributes are manipulated (3). The real work is done in (4): The URL is selected with <hask>getChildren</hask>, a text node, and converted into a string (<hask>xshow</hask>), the URL is transformed into an absolute URL<br />
with <hask>mkAbsURI</hask> (6). This arrow may fail, e.g. in case of illegal<br />
URLs. In this case the URL remains unchanged (<hask>`orElse` this</hask>).<br />
The resulting String value is converted into a text node forming the new<br />
attribute value node (7).<br />
<br />
Because of the use of the use of the global HXT state in <hask>mkAbsURI</hask><br />
<hask>mkAbsRef</hask> and <hask>imageTable2</hask> need to have the more specialized signature <hask>IOStateArrow s XmlTree XmlTree</hask>.<br />
<br />
== Transformation examples ==<br />
<br />
=== Decorating external references of an HTML document ===<br />
<br />
In the following examples, we want to decorate the external references<br />
in an HTML page by a small icon, like it's done in many wikis.<br />
For this task the document tree has to be traversed, all parts<br />
except the intersting A-Elements remain unchanged. At the end of the list of children of an A-Element we add an image element.<br />
<br />
Here is the first version:<br />
<br />
<haskell><br />
addRefIcon :: ArrowXml a => a XmlTree XmlTree<br />
addRefIcon<br />
= processTopDown -- (1)<br />
( addImg -- (2)<br />
`when`<br />
isExternalRef -- (3)<br />
)<br />
where<br />
isExternalRef -- (4)<br />
= isElem<br />
>>><br />
hasName "a"<br />
>>><br />
hasAttr "href"<br />
>>><br />
getAttrValue "href"<br />
>>><br />
isA isExtRef<br />
where<br />
isExtRef -- (4.1)<br />
= isPrefixOf "http:" -- or something more precise<br />
<br />
addImg<br />
= replaceChildren -- (5)<br />
( getChildren -- (6)<br />
<+><br />
imgElement -- (7)<br />
)<br />
<br />
imgElement<br />
= mkelem "img" -- (8)<br />
[ sattr "src" "/icons/ref.png" -- (9)<br />
, sattr "alt" "external ref"<br />
] [] -- (10)<br />
</haskell><br />
<br />
The traversal is done with <hask>processTopDown</hask> (1).<br />
This arrow applies an arrow to all nodes of the whole document tree.<br />
The transformation arrow applies the <hask>addImg</hask> (2) to<br />
all A-elements (3),(4). This arrow uses a bit simplified test (4.1)<br />
for external URLs.<br />
<hask>addImg</hask> manipulates all children (5) of the A-elements by<br />
selecting the current children (6) and adding an image element (7).<br />
The image element is constructed with <hask>mkelem</hask> (8). This takes<br />
an element name, a list of arrows for computing the attributes and a<br />
list of arrows for computing the contents. The content of the image element is<br />
empty (10). The attributes are constructed with <hask>sattr</hask> (9).<br />
<hask>sattr</hask> ignores the arrow input and builds an attribute form<br />
the name value pair of arguments.<br />
<br />
=== Transform external references into absolute references ===<br />
<br />
In the following example we will develop a programm for<br />
editing a HTML page such that all references to external documents<br />
(images, hypertext refs, style refs, ...) become absolute references.<br />
We will see some new, but very useful combinators in the solution.<br />
<br />
The task seems to be rather trivial. In a tree travaersal<br />
all references are edited with respect to the document base.<br />
But in HTML there is a BASE element, allowed in the content of HEAD<br />
with a HREF attribute, which defines the document base. Again this<br />
href can be a relative URL.<br />
<br />
We start the development with the editing arrow. This gets<br />
the real document base as argument.<br />
<br />
<haskell><br />
mkAbsHRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsHRefs base<br />
= processTopDown editHRef -- (1)<br />
where<br />
editHRef<br />
= processAttrl -- (3)<br />
( changeAttrValue (absHRef base) -- (5)<br />
`when`<br />
hasName "href" -- (4)<br />
)<br />
`when`<br />
( isElem >>> hasName "a" ) -- (2)<br />
where<br />
<br />
absHRef :: String -> String -> String -- (5)<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
The tree is traversed (1) and for every A element the attribute<br />
list is processed (2). All HREF attribute values (4) are manipulated<br />
by <hask>changeAttrValue</hask> called with a string function (5).<br />
<hask>expandURIString</hask> is a pure function defined in HXT for computing<br />
an absolut URI.<br />
In this first step we only edit A-HREF attribute values. We will refine this<br />
later.<br />
<br />
The second step is the complete computation of the base URL.<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( isElem >>> hasName "html" -- (0)<br />
>>><br />
getChildren -- (1)<br />
>>><br />
isElem >>> hasName "head" -- (2)<br />
>>><br />
getChildren -- (3)<br />
>>><br />
isElem >>> hasName "base" -- (4)<br />
>>><br />
getAttrValue "href" -- (5)<br />
)<br />
&&&<br />
getBaseURI -- (6)<br />
)<br />
>>> expandURI -- (7)<br />
)<br />
`orElse` getBaseURI -- (8)<br />
</haskell><br />
<br />
Input to this arrow is the HTML element, (0) to (5) is the arrow for selecting<br />
the BASE elements HREF value, parallel to this the system base URL is read<br />
with <hask>getBaseURI</hask> (6) like in examples above. The resulting <br />
pair of strings is piped into <hask>expandURI</hask> (7), the arrow version of<br />
<hask>expandURIString</hask>. This arrow ((1) to (7)) fails in the absense<br />
of a BASE element. in this case we take the plain document base (8).<br />
The selection of the BASE elements is not yet very handy. We will define<br />
a more general and elegant function later, allowing an element path as selection argument.<br />
<br />
In the third step, we will combine the to arrows. For this we will use<br />
a new combinator <hask>($<)</hask>. The need for this new combinator<br />
is the following: We need the arrow input (the document) two times,<br />
once for computing the document base, and second for editing the<br />
whole document, and we want to compute the extra string parameter<br />
for editing of course with the above defined arrow.<br />
<br />
The combined arrow, our main arrow, looks like this<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= mkAbsHRefs $< computeBaseRef -- (1)<br />
</haskell><br />
<br />
In (1) first the arrow input is piped into <hask>computeBaseRef</hask>,<br />
this result is used in <hask>mkAbsHRefs</hask> as extra string parameter<br />
when processing the document. Internally the <hask>($<)</hask> combinator<br />
is defined by the basic combinators <hask>(&&&), (>>>)</hask> and <hask>app</hask>, but in a bit more complex computations,<br />
this pattern occurs rather frequently, so ($<) becomes very useful.<br />
<br />
Programming with arrows is one style of point free programming. Point free<br />
programming often becomes unhandy when values are used more than once.<br />
One solution is the special arrow syntax supported by ghc and others, similar to the do notation for monads. But for many simple cases the <hask>($<)</hask> combinator and it's variants <hask>($<<), ($<<<), ($<<<<), ($<$)</hask><br />
is sufficient.<br />
<br />
To complete the development of the example, a last step is neccessary:<br />
The removal of the redundant BASE element.<br />
<br />
<haskell><br />
toAbsRefs :: IOStateArrow s XmlTree XmlTree<br />
toAbsRefs<br />
= ( mkAbsHRefs $< computeBaseRef )<br />
>>><br />
removeBaseElement<br />
<br />
removeBaseElement :: ArrowXml a => a XmlTree XmlTree<br />
removeBaseElement<br />
= processChildren<br />
( processChildren<br />
( none -- (1)<br />
`when`<br />
( isElem >>> hasName "base" )<br />
)<br />
`when`<br />
( isElem >>> hasName "head" )<br />
)<br />
</haskell><br />
<br />
In this function the children of the HEAD element are searched for<br />
a BASE element. This is removed by aplying the null arrow <hask>none</hask><br />
to the input, returning always the empty list.<br />
<hask>none `when` ...</hask> is the pattern for deleting nodes from a tree.<br />
<br />
The <hask>computeBaseRef</hask> function defined above contains an arrow pattern<br />
for selecting the right subtree that is rather common in HXT applications<br />
<br />
<haskell><br />
isElem >>> hasName n1<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName n2<br />
...<br />
>>><br />
getChildren<br />
>>><br />
isElem >>> hasName nm<br />
</haskell><br />
<br />
For this pattern we will define a convenient function creating the<br />
arrow for selection<br />
<br />
<haskell><br />
getDescendents :: ArrowXml a => [String] -> a XmlTree XmlTree<br />
getDescendents<br />
= foldl1 (\ x y -> x >>> getChildren >>> y) -- (1)<br />
.<br />
map (\ n -> isElem >>> hasName n) -- (2)<br />
</haskell><br />
<br />
The name list is mapped to the element checking arrow (2),<br />
the resulting list of arrows is folded with <hask>getChildren</hask><br />
into a single arrow. <hask>computeBaseRef</hask> can then be simplified<br />
and becomes more readable:<br />
<br />
<haskell><br />
computeBaseRef :: IOStateArrow s XmlTree String<br />
computeBaseRef<br />
= ( ( ( getDescendents ["html","head","base"] -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
...<br />
</haskell><br />
<br />
An even more general and flexible technic are the XPath expressions<br />
available for selection of document parts defined in the module<br />
<hask>Text.XML.HXT.Arrow.XmlNodeSet</hask>.<br />
<br />
With XPath <hask>computeBaseRef</hask> can be simplified to<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( ( getXPathTrees "/html/head/base" -- (1)<br />
>>><br />
getAttrValue "href" -- (2)<br />
)<br />
...<br />
</haskell><br />
<br />
Even the attribute selection can be expressed by XPath,<br />
so (1) and (2) can be combined into<br />
<br />
<haskell><br />
computeBaseRef<br />
= ( ( xshow (getXPathTrees "/html/head/base@href")<br />
...<br />
</haskell><br />
<br />
The extra <hask>xshow</hask> is here required to convert the<br />
XPath result, an XmlTree, into a string.<br />
<br />
XPath defines a<br />
full language for selecting parts of an XML document.<br />
Sometimes it's rather comfortable to make selections of this<br />
type, but the XPath evaluation in general is more expensive<br />
in time and space than a simple combination of arrows, like we've<br />
seen it in <hask>getDescendends</hask>.<br />
<br />
=== Transform external references into absolute references: Refinement ===<br />
<br />
In the above example only A-HREF URLs are edited. Now we extend this<br />
to other element-attribute combinations.<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown ( editRef "a" "href" -- (2)<br />
>>><br />
editRef "img" "src" -- (3)<br />
>>><br />
editRef "link" "href" -- (4)<br />
>>><br />
editRef "script" "src" -- (5)<br />
)<br />
where<br />
editRef en an -- (1)<br />
= processAttrl ( changeAttrValue (absHRef base)<br />
`when`<br />
hasName an<br />
)<br />
`when`<br />
( isElem >>> hasName en )<br />
where<br />
absHRef :: String -> String -> String<br />
absHRef base url<br />
= fromMaybe url . expandURIString url $ base<br />
</haskell><br />
<br />
<hask>editRef</hask> is parameterized by the element and attribute names.<br />
The arrow applied to every element is extended to a sequence of<br />
<hask>editRef</hask>'s ((2)-(5)). Notice that the document is still traversed only once.<br />
To process all possible HTML elements,<br />
this sequence should be extended by further element-attribute pairs.<br />
<br />
This can further be simplified into<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= foldl (>>>) this<br />
.<br />
map (\ (en, an) -> editRef en an)<br />
$<br />
[ ("a", "href")<br />
, ("img", "src")<br />
, ("link", "href")<br />
, ("script", "src") -- and more<br />
]<br />
editRef<br />
= ...<br />
</haskell><br />
<br />
The <hask>foldl (>>>) this</hask> is defined in HXT as <hask>seqA</hask>,<br />
so the above code can be simplified to<br />
<br />
<haskell><br />
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree<br />
mkAbsRefs base<br />
= processTopDown editRefs<br />
where<br />
editRefs<br />
= seqA . map (uncurry editRef)<br />
$<br />
...<br />
</haskell><br />
<br />
== More complex examples ==<br />
<br />
''' to be done '''<br />
<br />
'''Question''': is there any way to write/read Haskell types to/from XML in HXT? HaXml has readXml and showXml, but I can't find any similar mechanism in HXT. Help! -- AlsonKemp</div>B7j0chttps://wiki.haskell.org/index.php?title=Talk:Cookbook&diff=11580Talk:Cookbook2007-02-25T17:09:23Z<p>B7j0c: </p>
<hr />
<div>==Size and direction of page==<br />
Personally, it seems to me that this will be a very large and overwhelming page if it is filled out with all the items in the TOC. What about having it as a gathering page, pointing to other cookbook pages that are subs of this? [[User:BrettGiles|BrettGiles]] 17:44, 22 February 2007 (UTC)<br />
<br />
==Focus on Haskell concepts as well as general tasks==<br />
I like the idea of selecting typical cookbook tasks and providing haskell code snippets. Also it might be useful to provide examples of certain haskell concepts that may not be related to a specific task, like "how to use Control.Monad", "how to use list comprehensions", "how to use STM" etc,.<br />
[[User:b7j0c|b7j0c]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Talk:Cookbook&diff=11579Talk:Cookbook2007-02-25T17:08:46Z<p>B7j0c: </p>
<hr />
<div>==Size and direction of page==<br />
Personally, it seems to me that this will be a very large and overwhelming page if it is filled out with all the items in the TOC. What about having it as a gathering page, pointing to other cookbook pages that are subs of this? [[User:BrettGiles|BrettGiles]] 17:44, 22 February 2007 (UTC)<br />
<br />
==Focus on Haskell concepts as well as general tasks==<br />
I like the idea of selecting typical cookbook tasks and providing haskell code snippets. Also it might be useful to provide examples of certain haskell concepts that may not be related to a specific task, like "how to use Control.Monad", "how to use list comprehensions", "how to use STM" etc,.</div>B7j0chttps://wiki.haskell.org/index.php?title=User:B7j0c&diff=9962User:B7j0c2007-01-08T06:01:29Z<p>B7j0c: </p>
<hr />
<div>my background is perl/systems hacking for a verY! large website for a verY! long time (11 years). maybe in another 11 years i will be an intermediate haskell hacker!</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/54A_to_60&diff=993599 questions/54A to 602007-01-05T21:20:26Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Binary trees ==<br />
<br />
A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves.<br />
<br />
http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/p67.gif<br />
<br />
== Problem 54A ==<br />
<br />
(*) Check whether a given term represents a binary tree<br />
<br />
In Prolog or Lisp, one writes a predicate to do this.<br />
<br />
Example in Lisp:<br />
<pre><br />
* (istree (a (b nil nil) nil))<br />
T<br />
* (istree (a (b nil nil)))<br />
NIL<br />
</pre><br />
<br />
In Haskell, we characterize binary trees with a datatype definition:<br />
<haskell><br />
data Tree a = Empty | Branch a (Tree a) (Tree a)<br />
deriving (Show, Eq)<br />
</haskell><br />
The above tree is represented as:<br />
<haskell><br />
tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)<br />
(Branch 'e' Empty Empty))<br />
(Branch 'c' Empty<br />
(Branch 'f' (Branch 'g' Empty Empty)<br />
Empty)))<br />
</haskell><br />
Other examples of binary trees:<br />
<haskell><br />
tree2 = Branch 'a' Empty Empty -- a binary tree consisting of a root node only<br />
<br />
tree3 = nil -- an empty binary tree<br />
<br />
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))<br />
(Branch 2 Empty Empty)<br />
</haskell><br />
The type system ensures that all terms of type <hask>Tree a</hask><br />
are binary trees: it is just not possible to construct an invalid tree<br />
with this type. Hence, it is redundant to introduce a predicate to<br />
check this property: it would always return <hask>True</hask>.<br />
<br />
== Problem 55 ==<br />
<br />
(**) Construct completely balanced binary trees<br />
<br />
In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Write a function cbal-tree to construct completely balanced binary trees for a given number of nodes. The predicate should generate all solutions via backtracking. Put the letter 'x' as information into all nodes of the tree.<br />
<br />
Example:<br />
<pre><br />
* cbal-tree(4,T).<br />
T = t(x, t(x, nil, nil), t(x, nil, t(x, nil, nil))) ;<br />
T = t(x, t(x, nil, nil), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell, whitespace and "comment diagrams" added for clarity and exposition:<br />
<pre><br />
*Main> cbalTree 4<br />
[<br />
-- permutation 1<br />
-- x<br />
-- / \<br />
-- x x<br />
-- \<br />
-- x<br />
Branch 'x' (Branch 'x' Empty Empty) <br />
(Branch 'x' Empty <br />
(Branch 'x' Empty Empty)),<br />
<br />
-- permutation 2<br />
-- x<br />
-- / \<br />
-- x x<br />
-- /<br />
-- x<br />
Branch 'x' (Branch 'x' Empty Empty) <br />
(Branch 'x' (Branch 'x' Empty Empty) <br />
Empty),<br />
<br />
-- permutation 3<br />
-- x<br />
-- / \<br />
-- x x<br />
-- \<br />
-- x<br />
Branch 'x' (Branch 'x' Empty <br />
(Branch 'x' Empty Empty)) <br />
(Branch 'x' Empty Empty),<br />
<br />
-- permutation 4<br />
-- x<br />
-- / \<br />
-- x x<br />
-- /<br />
-- x<br />
Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) <br />
Empty) <br />
(Branch 'x' Empty Empty)<br />
]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
cbalTree 0 = [Empty]<br />
cbalTree n = [Branch 'x' l r | i <- [q .. q + r], l <- cbalTree i, r <- cbalTree (n - i - 1)]<br />
where (q, r) = quotRem (n-1) 2<br />
</haskell><br />
<br />
Here we use the list monad to enumerate all the trees, in a style that is more natural than standard backtracking.<br />
<br />
== Problem 56 ==<br />
<br />
(**) Symmetric binary trees<br />
<br />
Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)<br />
False<br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
mirror Empty Empty = True<br />
mirror (Branch _ a b) (Branch _ x y) = mirror a y && mirror b x<br />
mirror _ _ = False<br />
<br />
symmetric Empty = True<br />
symmetric (Branch _ l r) = mirror l r<br />
</haskell><br />
<br />
== Problem 57 ==<br />
<br />
(**) Binary search trees (dictionaries)<br />
<br />
Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.<br />
<br />
Example:<br />
<pre><br />
* construct([3,2,5,7,1],T).<br />
T = t(3, t(2, t(1, nil, nil), nil), t(5, nil, t(7, nil, nil)))<br />
</pre><br />
<br />
Then use this predicate to test the solution of the problem P56.<br />
<br />
Example:<br />
<pre><br />
* test-symmetric([5,3,18,1,4,12,21]).<br />
Yes<br />
* test-symmetric([3,2,5,7,1]).<br />
No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> construct [3, 2, 5, 7, 1]<br />
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))<br />
*Main> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]<br />
True<br />
*Main> symmetric . construct $ [3, 2, 5, 7, 1]<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
add :: Ord a => a -> Tree a -> Tree a<br />
add x Empty = Branch x Empty Empty<br />
add x t@(Branch y l r) = case compare x y of<br />
LT -> Branch y (add x l) r<br />
GT -> Branch y l (add x r)<br />
EQ -> t<br />
<br />
construct xs = foldl (flip add) Empty xs<br />
</haskell><br />
<br />
Here, the definition of construct is trivial, because the pattern of accumulating from the left is captured by the standard function foldl.<br />
<br />
== Problem 58 ==<br />
<br />
(**) Generate-and-test paradigm<br />
<br />
Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.<br />
<br />
Example:<br />
<pre><br />
* sym-cbal-trees(5,Ts).<br />
Ts = [t(x, t(x, nil, t(x, nil, nil)), t(x, t(x, nil, nil), nil)), t(x, t(x, t(x, nil, nil), nil), t(x, nil, t(x, nil, nil)))] <br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symCbalTrees 5<br />
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
symCbalTrees = filter symmetric . cbalTree<br />
</haskell><br />
<br />
== Problem 59 ==<br />
<br />
(**) Construct height-balanced binary trees<br />
<br />
In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Example:<br />
<pre><br />
?- hbal_tree(3,T).<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), t(x, nil, nil))) ;<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> take 4 $ hbalTree 'x' 3<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTree x = map fst . hbalTree'<br />
where hbalTree' 0 = [(Empty, 0)]<br />
hbalTree' 1 = [(Branch x Empty Empty, 1)]<br />
hbalTree' n =<br />
let t = hbalTree' (n-2) ++ hbalTree' (n-1)<br />
in [(Branch x lb rb, h) | (lb,lh) <- t, (rb,rh) <- t<br />
, let h = 1 + max lh rh, h == n]<br />
</haskell><br />
Alternative solution:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x 0 = [Empty]<br />
hbaltree x 1 = [Branch x Empty Empty]<br />
hbaltree x h = [Branch x l r |<br />
(hl, hr) <- [(h-2, h-1), (h-1, h-1), (h-1, h-2)],<br />
l <- hbaltree x hl, r <- hbaltree x hr]<br />
</haskell><br />
If we want to avoid recomputing lists of trees (at the cost of extra space), we can use a similar structure to the common method for computation of all the Fibonacci numbers:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x h = trees !! h<br />
where trees = [Empty] : [Branch x Empty Empty] :<br />
zipWith combine (tail trees) trees<br />
combine ts shortts = [Branch x l r |<br />
(ls, rs) <- [(shortts, ts), (ts, ts), (ts, shortts)],<br />
l <- ls, r <- rs]<br />
</haskell><br />
<br />
== Problem 60 ==<br />
<br />
(**) Construct height-balanced binary trees with a given number of nodes<br />
Consider a height-balanced binary tree of height H.<br />
What is the maximum number of nodes it can contain?<br />
Clearly, MaxN = 2**H - 1.<br />
However, what is the minimum number MinN?<br />
This question is more difficult.<br />
Try to find a recursive statement and turn it into a function <hask>minNodes</hask> that returns the minimum number of nodes in a height-balanced binary tree of height H.<br />
<br />
On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have?<br />
Write a function <hask>maxHeight</hask> that computes this.<br />
<br />
Now, we can attack the main problem: construct all the height-balanced binary trees with a given nuber of nodes.<br />
<br />
Find out how many height-balanced trees exist for N = 15.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- count_hbal_trees(15,C).<br />
C = 1553<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> length $ hbalTreeNodes 'x' 15<br />
1553<br />
*Main> map (hbalTreeNodes 'x') [0,1,2,3]<br />
[[Empty],<br />
[Branch 'x' Empty Empty],<br />
[Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTreeNodes _ 0 = [Empty]<br />
hbalTreeNodes x n = concatMap toFilteredTrees [minHeight .. maxHeight]<br />
where toFilteredTrees = filter ((n ==) . countNodes) . hbalTree x<br />
<br />
-- Similar to the Fibonacci sequence but adds 1 in each step.<br />
minNodesSeq = 0:1:zipWith ((+).(1+)) minNodesSeq (tail minNodesSeq)<br />
minNodes = (minNodesSeq !!)<br />
<br />
minHeight = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
maxHeight = (fromJust $ findIndex (>n) minNodesSeq) - 1<br />
<br />
countNodes Empty = 0<br />
countNodes (Branch _ l r) = countNodes l + countNodes r + 1<br />
<br />
</haskell><br />
Another solution generates only the trees we want:<br />
<haskell><br />
-- maximum number of nodes in a weight-balanced tree of height h<br />
maxNodes :: Int -> Int<br />
maxNodes h = 2^h - 1<br />
<br />
-- minimum height of a weight-balanced tree of n nodes<br />
minHeight :: Int -> Int<br />
minHeight n = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
<br />
-- minimum number of nodes in a weight-balanced tree of height h<br />
minNodes :: Int -> Int<br />
minNodes h = fibs !! (h+2) - 1<br />
<br />
-- maximum height of a weight-balanced tree of n nodes<br />
maxHeight :: Int -> Int<br />
maxHeight n = length (takeWhile (<= n+1) fibs) - 3<br />
<br />
-- Fibonacci numbers<br />
fibs :: [Int]<br />
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)<br />
<br />
hbalTreeNodes :: a -> Int -> [Tree a]<br />
hbalTreeNodes x n = [t | h <- [minHeight n .. maxHeight n], t <- baltree h n]<br />
where<br />
-- baltree h n = weight-balanced trees of height h with n nodes<br />
-- assuming minNodes h <= n <= maxNodes h<br />
baltree 0 n = [Empty]<br />
baltree 1 n = [Branch x Empty Empty]<br />
baltree h n = [Branch x l r |<br />
(hl,hr) <- [(h-2,h-1), (h-1,h-1), (h-1,h-2)],<br />
let min_nl = max (minNodes hl) (n - 1 - maxNodes hr),<br />
let max_nl = min (maxNodes hl) (n - 1 - minNodes hr),<br />
nl <- [min_nl .. max_nl],<br />
let nr = n - 1 - nl,<br />
l <- baltree hl nl,<br />
r <- baltree hr nr]<br />
</haskell><br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/54A_to_60&diff=993499 questions/54A to 602007-01-05T21:09:17Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Binary trees ==<br />
<br />
A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves.<br />
<br />
http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/p67.gif<br />
<br />
== Problem 54A ==<br />
<br />
(*) Check whether a given term represents a binary tree<br />
<br />
In Prolog or Lisp, one writes a predicate to do this.<br />
<br />
Example in Lisp:<br />
<pre><br />
* (istree (a (b nil nil) nil))<br />
T<br />
* (istree (a (b nil nil)))<br />
NIL<br />
</pre><br />
<br />
In Haskell, we characterize binary trees with a datatype definition:<br />
<haskell><br />
data Tree a = Empty | Branch a (Tree a) (Tree a)<br />
deriving (Show, Eq)<br />
</haskell><br />
The above tree is represented as:<br />
<haskell><br />
tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)<br />
(Branch 'e' Empty Empty))<br />
(Branch 'c' Empty<br />
(Branch 'f' (Branch 'g' Empty Empty)<br />
Empty)))<br />
</haskell><br />
Other examples of binary trees:<br />
<haskell><br />
tree2 = Branch 'a' Empty Empty -- a binary tree consisting of a root node only<br />
<br />
tree3 = nil -- an empty binary tree<br />
<br />
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))<br />
(Branch 2 Empty Empty)<br />
</haskell><br />
The type system ensures that all terms of type <hask>Tree a</hask><br />
are binary trees: it is just not possible to construct an invalid tree<br />
with this type. Hence, it is redundant to introduce a predicate to<br />
check this property: it would always return <hask>True</hask>.<br />
<br />
== Problem 55 ==<br />
<br />
(**) Construct completely balanced binary trees<br />
<br />
In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Write a function cbal-tree to construct completely balanced binary trees for a given number of nodes. The predicate should generate all solutions via backtracking. Put the letter 'x' as information into all nodes of the tree.<br />
<br />
Example:<br />
<pre><br />
* cbal-tree(4,T).<br />
T = t(x, t(x, nil, nil), t(x, nil, t(x, nil, nil))) ;<br />
T = t(x, t(x, nil, nil), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell, whitespace added for clarity:<br />
<pre><br />
*Main> cbalTree 4<br />
[<br />
Branch 'x' (Branch 'x' Empty Empty) <br />
(Branch 'x' Empty <br />
(Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty Empty) <br />
(Branch 'x' (Branch 'x' Empty Empty) <br />
Empty),<br />
Branch 'x' (Branch 'x' Empty <br />
(Branch 'x' Empty Empty)) <br />
(Branch 'x' Empty Empty),<br />
Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) <br />
Empty) <br />
(Branch 'x' Empty Empty)<br />
]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
cbalTree 0 = [Empty]<br />
cbalTree n = [Branch 'x' l r | i <- [q .. q + r], l <- cbalTree i, r <- cbalTree (n - i - 1)]<br />
where (q, r) = quotRem (n-1) 2<br />
</haskell><br />
<br />
Here we use the list monad to enumerate all the trees, in a style that is more natural than standard backtracking.<br />
<br />
== Problem 56 ==<br />
<br />
(**) Symmetric binary trees<br />
<br />
Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)<br />
False<br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
mirror Empty Empty = True<br />
mirror (Branch _ a b) (Branch _ x y) = mirror a y && mirror b x<br />
mirror _ _ = False<br />
<br />
symmetric Empty = True<br />
symmetric (Branch _ l r) = mirror l r<br />
</haskell><br />
<br />
== Problem 57 ==<br />
<br />
(**) Binary search trees (dictionaries)<br />
<br />
Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.<br />
<br />
Example:<br />
<pre><br />
* construct([3,2,5,7,1],T).<br />
T = t(3, t(2, t(1, nil, nil), nil), t(5, nil, t(7, nil, nil)))<br />
</pre><br />
<br />
Then use this predicate to test the solution of the problem P56.<br />
<br />
Example:<br />
<pre><br />
* test-symmetric([5,3,18,1,4,12,21]).<br />
Yes<br />
* test-symmetric([3,2,5,7,1]).<br />
No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> construct [3, 2, 5, 7, 1]<br />
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))<br />
*Main> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]<br />
True<br />
*Main> symmetric . construct $ [3, 2, 5, 7, 1]<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
add :: Ord a => a -> Tree a -> Tree a<br />
add x Empty = Branch x Empty Empty<br />
add x t@(Branch y l r) = case compare x y of<br />
LT -> Branch y (add x l) r<br />
GT -> Branch y l (add x r)<br />
EQ -> t<br />
<br />
construct xs = foldl (flip add) Empty xs<br />
</haskell><br />
<br />
Here, the definition of construct is trivial, because the pattern of accumulating from the left is captured by the standard function foldl.<br />
<br />
== Problem 58 ==<br />
<br />
(**) Generate-and-test paradigm<br />
<br />
Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.<br />
<br />
Example:<br />
<pre><br />
* sym-cbal-trees(5,Ts).<br />
Ts = [t(x, t(x, nil, t(x, nil, nil)), t(x, t(x, nil, nil), nil)), t(x, t(x, t(x, nil, nil), nil), t(x, nil, t(x, nil, nil)))] <br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symCbalTrees 5<br />
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
symCbalTrees = filter symmetric . cbalTree<br />
</haskell><br />
<br />
== Problem 59 ==<br />
<br />
(**) Construct height-balanced binary trees<br />
<br />
In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Example:<br />
<pre><br />
?- hbal_tree(3,T).<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), t(x, nil, nil))) ;<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> take 4 $ hbalTree 'x' 3<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTree x = map fst . hbalTree'<br />
where hbalTree' 0 = [(Empty, 0)]<br />
hbalTree' 1 = [(Branch x Empty Empty, 1)]<br />
hbalTree' n =<br />
let t = hbalTree' (n-2) ++ hbalTree' (n-1)<br />
in [(Branch x lb rb, h) | (lb,lh) <- t, (rb,rh) <- t<br />
, let h = 1 + max lh rh, h == n]<br />
</haskell><br />
Alternative solution:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x 0 = [Empty]<br />
hbaltree x 1 = [Branch x Empty Empty]<br />
hbaltree x h = [Branch x l r |<br />
(hl, hr) <- [(h-2, h-1), (h-1, h-1), (h-1, h-2)],<br />
l <- hbaltree x hl, r <- hbaltree x hr]<br />
</haskell><br />
If we want to avoid recomputing lists of trees (at the cost of extra space), we can use a similar structure to the common method for computation of all the Fibonacci numbers:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x h = trees !! h<br />
where trees = [Empty] : [Branch x Empty Empty] :<br />
zipWith combine (tail trees) trees<br />
combine ts shortts = [Branch x l r |<br />
(ls, rs) <- [(shortts, ts), (ts, ts), (ts, shortts)],<br />
l <- ls, r <- rs]<br />
</haskell><br />
<br />
== Problem 60 ==<br />
<br />
(**) Construct height-balanced binary trees with a given number of nodes<br />
Consider a height-balanced binary tree of height H.<br />
What is the maximum number of nodes it can contain?<br />
Clearly, MaxN = 2**H - 1.<br />
However, what is the minimum number MinN?<br />
This question is more difficult.<br />
Try to find a recursive statement and turn it into a function <hask>minNodes</hask> that returns the minimum number of nodes in a height-balanced binary tree of height H.<br />
<br />
On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have?<br />
Write a function <hask>maxHeight</hask> that computes this.<br />
<br />
Now, we can attack the main problem: construct all the height-balanced binary trees with a given nuber of nodes.<br />
<br />
Find out how many height-balanced trees exist for N = 15.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- count_hbal_trees(15,C).<br />
C = 1553<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> length $ hbalTreeNodes 'x' 15<br />
1553<br />
*Main> map (hbalTreeNodes 'x') [0,1,2,3]<br />
[[Empty],<br />
[Branch 'x' Empty Empty],<br />
[Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTreeNodes _ 0 = [Empty]<br />
hbalTreeNodes x n = concatMap toFilteredTrees [minHeight .. maxHeight]<br />
where toFilteredTrees = filter ((n ==) . countNodes) . hbalTree x<br />
<br />
-- Similar to the Fibonacci sequence but adds 1 in each step.<br />
minNodesSeq = 0:1:zipWith ((+).(1+)) minNodesSeq (tail minNodesSeq)<br />
minNodes = (minNodesSeq !!)<br />
<br />
minHeight = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
maxHeight = (fromJust $ findIndex (>n) minNodesSeq) - 1<br />
<br />
countNodes Empty = 0<br />
countNodes (Branch _ l r) = countNodes l + countNodes r + 1<br />
<br />
</haskell><br />
Another solution generates only the trees we want:<br />
<haskell><br />
-- maximum number of nodes in a weight-balanced tree of height h<br />
maxNodes :: Int -> Int<br />
maxNodes h = 2^h - 1<br />
<br />
-- minimum height of a weight-balanced tree of n nodes<br />
minHeight :: Int -> Int<br />
minHeight n = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
<br />
-- minimum number of nodes in a weight-balanced tree of height h<br />
minNodes :: Int -> Int<br />
minNodes h = fibs !! (h+2) - 1<br />
<br />
-- maximum height of a weight-balanced tree of n nodes<br />
maxHeight :: Int -> Int<br />
maxHeight n = length (takeWhile (<= n+1) fibs) - 3<br />
<br />
-- Fibonacci numbers<br />
fibs :: [Int]<br />
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)<br />
<br />
hbalTreeNodes :: a -> Int -> [Tree a]<br />
hbalTreeNodes x n = [t | h <- [minHeight n .. maxHeight n], t <- baltree h n]<br />
where<br />
-- baltree h n = weight-balanced trees of height h with n nodes<br />
-- assuming minNodes h <= n <= maxNodes h<br />
baltree 0 n = [Empty]<br />
baltree 1 n = [Branch x Empty Empty]<br />
baltree h n = [Branch x l r |<br />
(hl,hr) <- [(h-2,h-1), (h-1,h-1), (h-1,h-2)],<br />
let min_nl = max (minNodes hl) (n - 1 - maxNodes hr),<br />
let max_nl = min (maxNodes hl) (n - 1 - minNodes hr),<br />
nl <- [min_nl .. max_nl],<br />
let nr = n - 1 - nl,<br />
l <- baltree hl nl,<br />
r <- baltree hr nr]<br />
</haskell><br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/54A_to_60&diff=993399 questions/54A to 602007-01-05T20:58:47Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Binary trees ==<br />
<br />
A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves.<br />
<br />
http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/p67.gif<br />
<br />
== Problem 54A ==<br />
<br />
(*) Check whether a given term represents a binary tree<br />
<br />
In Prolog or Lisp, one writes a predicate to do this.<br />
<br />
Example in Lisp:<br />
<pre><br />
* (istree (a (b nil nil) nil))<br />
T<br />
* (istree (a (b nil nil)))<br />
NIL<br />
</pre><br />
<br />
In Haskell, we characterize binary trees with a datatype definition:<br />
<haskell><br />
data Tree a = Empty | Branch a (Tree a) (Tree a)<br />
deriving (Show, Eq)<br />
</haskell><br />
The above tree is represented as:<br />
<haskell><br />
tree1 = Branch 'a' (Branch 'b' (Branch 'd' Empty Empty)<br />
(Branch 'e' Empty Empty))<br />
(Branch 'c' Empty<br />
(Branch 'f' (Branch 'g' Empty Empty)<br />
Empty)))<br />
</haskell><br />
Other examples of binary trees:<br />
<haskell><br />
tree2 = Branch 'a' Empty Empty -- a binary tree consisting of a root node only<br />
<br />
tree3 = nil -- an empty binary tree<br />
<br />
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))<br />
(Branch 2 Empty Empty)<br />
</haskell><br />
The type system ensures that all terms of type <hask>Tree a</hask><br />
are binary trees: it is just not possible to construct an invalid tree<br />
with this type. Hence, it is redundant to introduce a predicate to<br />
check this property: it would always return <hask>True</hask>.<br />
<br />
== Problem 55 ==<br />
<br />
(**) Construct completely balanced binary trees<br />
<br />
In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Write a function cbal-tree to construct completely balanced binary trees for a given number of nodes. The predicate should generate all solutions via backtracking. Put the letter 'x' as information into all nodes of the tree.<br />
<br />
Example:<br />
<pre><br />
* cbal-tree(4,T).<br />
T = t(x, t(x, nil, nil), t(x, nil, t(x, nil, nil))) ;<br />
T = t(x, t(x, nil, nil), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> cbalTree 4<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty Empty)]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
cbalTree 0 = [Empty]<br />
cbalTree n = [Branch 'x' l r | i <- [q .. q + r], l <- cbalTree i, r <- cbalTree (n - i - 1)]<br />
where (q, r) = quotRem (n-1) 2<br />
</haskell><br />
<br />
Here we use the list monad to enumerate all the trees, in a style that is more natural than standard backtracking.<br />
<br />
== Problem 56 ==<br />
<br />
(**) Symmetric binary trees<br />
<br />
Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a predicate symmetric/1 to check whether a given binary tree is symmetric. Hint: Write a predicate mirror/2 first to check whether one tree is the mirror image of another. We are only interested in the structure, not in the contents of the nodes.<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) Empty)<br />
False<br />
*Main> symmetric (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty))<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
mirror Empty Empty = True<br />
mirror (Branch _ a b) (Branch _ x y) = mirror a y && mirror b x<br />
mirror _ _ = False<br />
<br />
symmetric Empty = True<br />
symmetric (Branch _ l r) = mirror l r<br />
</haskell><br />
<br />
== Problem 57 ==<br />
<br />
(**) Binary search trees (dictionaries)<br />
<br />
Use the predicate add/3, developed in chapter 4 of the course, to write a predicate to construct a binary search tree from a list of integer numbers.<br />
<br />
Example:<br />
<pre><br />
* construct([3,2,5,7,1],T).<br />
T = t(3, t(2, t(1, nil, nil), nil), t(5, nil, t(7, nil, nil)))<br />
</pre><br />
<br />
Then use this predicate to test the solution of the problem P56.<br />
<br />
Example:<br />
<pre><br />
* test-symmetric([5,3,18,1,4,12,21]).<br />
Yes<br />
* test-symmetric([3,2,5,7,1]).<br />
No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> construct [3, 2, 5, 7, 1]<br />
Branch 3 (Branch 2 (Branch 1 Empty Empty) Empty) (Branch 5 Empty (Branch 7 Empty Empty))<br />
*Main> symmetric . construct $ [5, 3, 18, 1, 4, 12, 21]<br />
True<br />
*Main> symmetric . construct $ [3, 2, 5, 7, 1]<br />
True<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
add :: Ord a => a -> Tree a -> Tree a<br />
add x Empty = Branch x Empty Empty<br />
add x t@(Branch y l r) = case compare x y of<br />
LT -> Branch y (add x l) r<br />
GT -> Branch y l (add x r)<br />
EQ -> t<br />
<br />
construct xs = foldl (flip add) Empty xs<br />
</haskell><br />
<br />
Here, the definition of construct is trivial, because the pattern of accumulating from the left is captured by the standard function foldl.<br />
<br />
== Problem 58 ==<br />
<br />
(**) Generate-and-test paradigm<br />
<br />
Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes.<br />
<br />
Example:<br />
<pre><br />
* sym-cbal-trees(5,Ts).<br />
Ts = [t(x, t(x, nil, t(x, nil, nil)), t(x, t(x, nil, nil), nil)), t(x, t(x, t(x, nil, nil), nil), t(x, nil, t(x, nil, nil)))] <br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> symCbalTrees 5<br />
[Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' (Branch 'x' Empty Empty) Empty),Branch 'x' (Branch 'x' (Branch 'x' Empty Empty) Empty) (Branch 'x' Empty (Branch 'x' Empty Empty))]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
symCbalTrees = filter symmetric . cbalTree<br />
</haskell><br />
<br />
== Problem 59 ==<br />
<br />
(**) Construct height-balanced binary trees<br />
<br />
In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.<br />
<br />
Example:<br />
<pre><br />
?- hbal_tree(3,T).<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), t(x, nil, nil))) ;<br />
T = t(x, t(x, t(x, nil, nil), t(x, nil, nil)), t(x, t(x, nil, nil), nil)) ;<br />
etc......No<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> take 4 $ hbalTree 'x' 3<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) Empty),<br />
Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)),<br />
Branch 'x' (Branch 'x' Empty (Branch 'x' Empty Empty)) (Branch 'x' Empty Empty)]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTree x = map fst . hbalTree'<br />
where hbalTree' 0 = [(Empty, 0)]<br />
hbalTree' 1 = [(Branch x Empty Empty, 1)]<br />
hbalTree' n =<br />
let t = hbalTree' (n-2) ++ hbalTree' (n-1)<br />
in [(Branch x lb rb, h) | (lb,lh) <- t, (rb,rh) <- t<br />
, let h = 1 + max lh rh, h == n]<br />
</haskell><br />
Alternative solution:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x 0 = [Empty]<br />
hbaltree x 1 = [Branch x Empty Empty]<br />
hbaltree x h = [Branch x l r |<br />
(hl, hr) <- [(h-2, h-1), (h-1, h-1), (h-1, h-2)],<br />
l <- hbaltree x hl, r <- hbaltree x hr]<br />
</haskell><br />
If we want to avoid recomputing lists of trees (at the cost of extra space), we can use a similar structure to the common method for computation of all the Fibonacci numbers:<br />
<haskell><br />
hbaltree :: a -> Int -> [Tree a]<br />
hbaltree x h = trees !! h<br />
where trees = [Empty] : [Branch x Empty Empty] :<br />
zipWith combine (tail trees) trees<br />
combine ts shortts = [Branch x l r |<br />
(ls, rs) <- [(shortts, ts), (ts, ts), (ts, shortts)],<br />
l <- ls, r <- rs]<br />
</haskell><br />
<br />
== Problem 60 ==<br />
<br />
(**) Construct height-balanced binary trees with a given number of nodes<br />
Consider a height-balanced binary tree of height H.<br />
What is the maximum number of nodes it can contain?<br />
Clearly, MaxN = 2**H - 1.<br />
However, what is the minimum number MinN?<br />
This question is more difficult.<br />
Try to find a recursive statement and turn it into a function <hask>minNodes</hask> that returns the minimum number of nodes in a height-balanced binary tree of height H.<br />
<br />
On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have?<br />
Write a function <hask>maxHeight</hask> that computes this.<br />
<br />
Now, we can attack the main problem: construct all the height-balanced binary trees with a given nuber of nodes.<br />
<br />
Find out how many height-balanced trees exist for N = 15.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- count_hbal_trees(15,C).<br />
C = 1553<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> length $ hbalTreeNodes 'x' 15<br />
1553<br />
*Main> map (hbalTreeNodes 'x') [0,1,2,3]<br />
[[Empty],<br />
[Branch 'x' Empty Empty],<br />
[Branch 'x' Empty (Branch 'x' Empty Empty),Branch 'x' (Branch 'x' Empty Empty) Empty],<br />
[Branch 'x' (Branch 'x' Empty Empty) (Branch 'x' Empty Empty)]]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
hbalTreeNodes _ 0 = [Empty]<br />
hbalTreeNodes x n = concatMap toFilteredTrees [minHeight .. maxHeight]<br />
where toFilteredTrees = filter ((n ==) . countNodes) . hbalTree x<br />
<br />
-- Similar to the Fibonacci sequence but adds 1 in each step.<br />
minNodesSeq = 0:1:zipWith ((+).(1+)) minNodesSeq (tail minNodesSeq)<br />
minNodes = (minNodesSeq !!)<br />
<br />
minHeight = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
maxHeight = (fromJust $ findIndex (>n) minNodesSeq) - 1<br />
<br />
countNodes Empty = 0<br />
countNodes (Branch _ l r) = countNodes l + countNodes r + 1<br />
<br />
</haskell><br />
Another solution generates only the trees we want:<br />
<haskell><br />
-- maximum number of nodes in a weight-balanced tree of height h<br />
maxNodes :: Int -> Int<br />
maxNodes h = 2^h - 1<br />
<br />
-- minimum height of a weight-balanced tree of n nodes<br />
minHeight :: Int -> Int<br />
minHeight n = ceiling $ logBase 2 $ fromIntegral (n+1)<br />
<br />
-- minimum number of nodes in a weight-balanced tree of height h<br />
minNodes :: Int -> Int<br />
minNodes h = fibs !! (h+2) - 1<br />
<br />
-- maximum height of a weight-balanced tree of n nodes<br />
maxHeight :: Int -> Int<br />
maxHeight n = length (takeWhile (<= n+1) fibs) - 3<br />
<br />
-- Fibonacci numbers<br />
fibs :: [Int]<br />
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)<br />
<br />
hbalTreeNodes :: a -> Int -> [Tree a]<br />
hbalTreeNodes x n = [t | h <- [minHeight n .. maxHeight n], t <- baltree h n]<br />
where<br />
-- baltree h n = weight-balanced trees of height h with n nodes<br />
-- assuming minNodes h <= n <= maxNodes h<br />
baltree 0 n = [Empty]<br />
baltree 1 n = [Branch x Empty Empty]<br />
baltree h n = [Branch x l r |<br />
(hl,hr) <- [(h-2,h-1), (h-1,h-1), (h-1,h-2)],<br />
let min_nl = max (minNodes hl) (n - 1 - maxNodes hr),<br />
let max_nl = min (maxNodes hl) (n - 1 - minNodes hr),<br />
nl <- [min_nl .. max_nl],<br />
let nr = n - 1 - nl,<br />
l <- baltree hl nl,<br />
r <- baltree hr nr]<br />
</haskell><br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Wanted_libraries&diff=9932Wanted libraries2007-01-05T20:58:17Z<p>B7j0c: </p>
<hr />
<div>This page provides a list of missing and found libraries for solving<br />
common ''real world'' programmer tasks.<br />
<br />
If you think there should be a library for some common task, add it to<br />
this page, and someone may well step up and write it. If you know of a<br />
library to solve an open problem domain, link to it.<br />
<br />
The first place to look is [[Libraries_and_tools|the full libraries list]].<br />
<br />
<br />
== Missing libraries (by problem domain) ==<br />
<br />
=== IMAP ===<br />
A functional IMAP library would be nice, particularly one that can be used in conjunction with encryption and authentication. References have been found to a SoC project although it appears to be derelict. <br />
<br />
=== Numerical algorithms ===<br />
Stuff to compute bessel functions, struve H1 etc.<br />
<br />
=== .NET/Java Interoperability ===<br />
We could use a .NET FFI library that lets you easily call into the .NET framework. Perhaps the (abandoned?) [http://galois.com/~sof/hugs98.net/ Hugs .NET FFI library] could be resurrected/updated and ported to GHC? Maybe a tool could even be created that automates the interoperability of Haskell and arbitrary .NET libraries?<br />
<br />
== Could be improved ==<br />
<br />
Problems with existing solutions, that could be improved.<br />
<br />
* The core HTTP libraries need a lot of work. There is the beginnings of a useful library there, but many http codes are not handled, and there should be simple 'get' and 'head' functionality. <br />
* Binary serialisation support should be ported to bytestring, and added to the extralibs bundle<br />
* Support for wider Word values in bytestring.<br />
* Adding bytestring support to Parsec.<br />
* Simple process forking/popen, of type <hask>String -> IO String</hask>, is needed (the implementation should be in base)<br />
<br />
If you have code that improves on something in the base libraries, you might consider [[Library_submissions|submitting it to the libraries process]], so it can appear in the standard libraries.<br />
<br />
== Existing libraries (by problem domain) ==<br />
<br />
See [[Libraries_and_tools|the full libraries list]].<br />
<br />
=== GUIs ===<br />
<br />
See [[Libraries_and_tools/GUI_libraries|GUI libraries]]<br />
<br />
=== High performance string IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Strings|String libraries]]<br />
<br />
=== Binary IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Serialising_data|Binary IO]]<br />
<br />
=== Compression ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Compressing_data|Compressing data]]<br />
<br />
=== Encryption ===<br />
<br />
See [[Libraries_and_tools/Cryptography|Crypto libraries]]<br />
<br />
=== Web frameworks ===<br />
<br />
See [[Libraries_and_tools/Web_programming#Web_frameworks|Web frameworks]]<br />
<br />
=== XML processing ===<br />
<br />
See [[Libraries_and_tools/Web_programming#XML|XML handling]]<br />
<br />
=== Database access ===<br />
<br />
See [[Libraries_and_tools/Database_interfaces|Databases]]<br />
<br />
<br />
Add more problem domains that you feel we need libraries for!</div>B7j0chttps://wiki.haskell.org/index.php?title=Wanted_libraries&diff=9931Wanted libraries2007-01-05T20:57:01Z<p>B7j0c: </p>
<hr />
<div>This page provides a list of missing and found libraries for solving<br />
common ''real world'' programmer tasks.<br />
<br />
If you think there should be a library for some common task, add it to<br />
this page, and someone may well step up and write it. If you know of a<br />
library to solve an open problem domain, link to it.<br />
<br />
The first place to look is [[Libraries_and_tools|the full libraries list]].<br />
<br />
<br />
== Missing libraries (by problem domain) ==<br />
<br />
A functional IMAP library. References have been found to a SoC project although it appears to be derelict. <br />
<br />
=== Numerical algorithms ===<br />
Stuff to compute bessel functions, struve H1 etc.<br />
<br />
=== .NET/Java Interoperability ===<br />
We could use a .NET FFI library that lets you easily call into the .NET framework. Perhaps the (abandoned?) [http://galois.com/~sof/hugs98.net/ Hugs .NET FFI library] could be resurrected/updated and ported to GHC? Maybe a tool could even be created that automates the interoperability of Haskell and arbitrary .NET libraries?<br />
<br />
== Could be improved ==<br />
<br />
Problems with existing solutions, that could be improved.<br />
<br />
* The core HTTP libraries need a lot of work. There is the beginnings of a useful library there, but many http codes are not handled, and there should be simple 'get' and 'head' functionality. <br />
* Binary serialisation support should be ported to bytestring, and added to the extralibs bundle<br />
* Support for wider Word values in bytestring.<br />
* Adding bytestring support to Parsec.<br />
* Simple process forking/popen, of type <hask>String -> IO String</hask>, is needed (the implementation should be in base)<br />
<br />
If you have code that improves on something in the base libraries, you might consider [[Library_submissions|submitting it to the libraries process]], so it can appear in the standard libraries.<br />
<br />
== Existing libraries (by problem domain) ==<br />
<br />
See [[Libraries_and_tools|the full libraries list]].<br />
<br />
=== GUIs ===<br />
<br />
See [[Libraries_and_tools/GUI_libraries|GUI libraries]]<br />
<br />
=== High performance string IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Strings|String libraries]]<br />
<br />
=== Binary IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Serialising_data|Binary IO]]<br />
<br />
=== Compression ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Compressing_data|Compressing data]]<br />
<br />
=== Encryption ===<br />
<br />
See [[Libraries_and_tools/Cryptography|Crypto libraries]]<br />
<br />
=== Web frameworks ===<br />
<br />
See [[Libraries_and_tools/Web_programming#Web_frameworks|Web frameworks]]<br />
<br />
=== XML processing ===<br />
<br />
See [[Libraries_and_tools/Web_programming#XML|XML handling]]<br />
<br />
=== Database access ===<br />
<br />
See [[Libraries_and_tools/Database_interfaces|Databases]]<br />
<br />
<br />
Add more problem domains that you feel we need libraries for!</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/21_to_28&diff=991399 questions/21 to 282007-01-05T06:20:44Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
<br />
== Problem 21 ==<br />
<br />
Insert an element at a given position into a list.<br />
<br />
<pre><br />
Example:<br />
* (insert-at 'alfa '(a b c d) 2)<br />
(A ALFA B C D)<br />
Example in Haskell:<br />
P21> insertAt 'X' "abcd" 2<br />
"aXbcd"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
insertAt :: a -> [a] -> Int -> [a]<br />
insertAt x xs (n+1) = let (ys,zs) = split xs n in ys++x:zs<br />
</haskell><br />
or<br />
<haskell><br />
insertAt :: a -> [a] -> Int -> [a]<br />
insertAt x ys 1 = x:ys<br />
insertAt x (y:ys) n = y:insertAt x ys (n-1)<br />
</haskell><br />
<br />
There are two possible simple solutions. First we can use <hask>split</hask> from problem 17 (or even <hask>splitAt</hask> from the Prelude) to split the list and insert the element. Second we can define a recursive solution on our own.<br />
<br />
As a note to the above solution - this presumes that the inserted argument will be a singleton type <tt>a</tt> inserted into a list <tt>[a]</tt>. The lisp example does not infer this intent. As a result, presuming the data to be inserted is likewise of type <tt>[a]</tt> (which we are tacitly inferring here to be String into String insertion), a solution is:<br />
<br />
<haskell><br />
insertAt x xs n = take (n-1) xs ++ x ++ drop (n-1) xs<br />
</haskell><br />
<br />
This solution, like many others in this quiz presumes counting element positions starts at 1, perhaps causing needless confusion.<br />
<br />
== Problem 22 ==<br />
<br />
Create a list containing all integers within a given range.<br />
<br />
<pre><br />
Example:<br />
* (range 4 9)<br />
(4 5 6 7 8 9)<br />
<br />
Example in Haskell:<br />
Prelude> [4..9]<br />
[4,5,6,7,8,9]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
range x y = [x..y]<br />
</haskell><br />
or<br />
<haskell><br />
range = enumFromTo<br />
</haskell><br />
or<br />
<haskell><br />
range x y = take (y-x+1) $ iterate (+1) x<br />
</haskell><br />
or<br />
<haskell><br />
range i k <br />
| i <= k = i : range (i + 1) k<br />
| i > k = []<br />
</haskell><br />
<br />
Since there's already syntactic sugar for ranges, there's usually no reason to define a function like 'range' in Haskell. In fact, the syntactic sugar is implemented using the enumFromTo function, which is exactly what 'range' should be.<br />
<br />
== Problem 23 ==<br />
<br />
Extract a given number of randomly selected elements from a list. <br />
<br />
<pre><br />
Example:<br />
* (rnd-select '(a b c d e f g h) 3)<br />
(E D A)<br />
<br />
Example in Haskell:<br />
Prelude System.Random>rnd_select "abcdefgh" 3 >>= putStrLn<br />
eda<br />
<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
import System.Random<br />
<br />
rnd_select :: [a]->Int->IO [a]<br />
rnd_select [] _ = return []<br />
rnd_select l n <br />
| n<0 = error "N must be greater than zero."<br />
| otherwise = do pos<-sequence$replicate n$getStdRandom$randomR (0,(length l)-1)<br />
return [l!!p | p<-pos]<br />
</haskell><br />
<br />
In order to use getStdRandom and randomR here, we need import module System.Random.<br />
<br />
or using sequence all the way:<br />
<haskell><br />
rnd_select xs n <br />
| n < 0 = error "N must be greater than zero."<br />
| otherwise = sequence $ replicate n rand<br />
where rand = do r <- randomRIO (0,(length xs) - 1)<br />
return (xs!!r)<br />
</haskell><br />
<br />
Alternative Solution:<br />
<br />
The original Lisp problem suggested we use our solution from problem 20. I believe that each item from the list should only appear once, whereas the above solution can reuse items.<br />
<br />
Therefore here is an alternative which uses the "removeAt" function from problem 20:<br />
<haskell><br />
rnd_select :: RandomGen g => [a] -> Int -> g -> ([a], g)<br />
rnd_select _ 0 gen = ([], gen)<br />
rnd_select [] _ gen = ([], gen)<br />
rnd_select l count gen<br />
| count == (length l) = (l, gen)<br />
| otherwise = rnd_select (removeAt k l) count gen'<br />
where (k, gen') = randomR (0, (length l) - 1) gen<br />
<br />
rnd_selectIO :: [a] -> Int -> IO [a]<br />
rnd_selectIO l count = getStdRandom $ rnd_select l count<br />
</haskell><br />
If the number of items we want is the same as the number of items in the list, then we just return the list. Otherwise we remove a random item from the list and then recurse.<br />
<br />
Another Alternative Solution:<br />
<br />
Since the above Alternative Solution works by removing things to create the target list, it's most efficient when the target list length is > (orig list / 2). Here's another solution that's efficient in the other way (target < (orig list / 2)) by constructing an accumulator list of selected random elements. (This one also uses removeAt from problem 20)<br />
<br />
<haskell><br />
rnd_select :: RandomGen g => [a] -> Int -> g -> ([a], g)<br />
rnd_select ol ocount ogen = rnd_select' ol [] ocount ogen<br />
where<br />
rnd_select' l acc count gen<br />
| count == 0 = (acc, gen)<br />
| otherwise = rnd_select' (removeAt k l) ((l !! k) : acc) <br />
(count - 1) gen'<br />
where (k, gen') = randomR (0, (length l) - 1) gen<br />
<br />
rnd_selectIO :: [a] -> Int -> IO [a]<br />
rnd_selectIO l count = getStdRandom $ rnd_select l count<br />
</haskell><br />
<br />
Note, all of these return IO [a]. Some recent version of GHCi added the ability to display <haskell>IO a</haskell> values at the top level. Hugs (and older GHCi) behaves differently, so an action to actually do IO (putStrLn in the example) is required.<br />
<br />
== Problem 24 ==<br />
<br />
Lotto: Draw N different random numbers from the set 1..M.<br />
<br />
<pre><br />
Example:<br />
* (rnd-select 6 49)<br />
(23 1 17 33 21 37)<br />
<br />
Example in Haskell:<br />
Prelude System.Random>diff_select 6 49<br />
Prelude System.Random>[23,1,17,33,21,37]<br />
<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
import System.Random<br />
diff_select :: Int -> Int -> IO [Int]<br />
diff_select n to = diff_select' n [1..to]<br />
<br />
diff_select' 0 _ = return []<br />
diff_select' _ [] = error "too few elements to choose from"<br />
diff_select' n xs = do r <- randomRIO (0,(length xs)-1)<br />
let remaining = take r xs ++ drop (r+1) xs<br />
rest <- diff_select' (n-1) remaining<br />
return ((xs!!r) : rest)<br />
</haskell><br />
<br />
The random numbers have to be distinct!<br />
<br />
In order to use getStdRandom and randomR here, we need import module System.Random.<br />
<br />
== Problem 25 ==<br />
<br />
Generate a random permutation of the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (rnd-permu '(a b c d e f))<br />
(B A D C E F)<br />
<br />
<br />
Example in Haskell:<br />
Prelude>rnd_permu "abcdef"<br />
Prelude>"badcef"<br />
<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rnd_permu xs = diff_select' (length xs) xs<br />
</haskell><br />
<br />
Uses the solution for the previous problem. Choosing N distinct elements from a list of length N will yield a permutation.<br />
<br />
== Problem 26 ==<br />
<br />
(**) Generate the combinations of K distinct objects chosen from the N elements of a list<br />
In how many ways can a committee of 3 be chosen from a group of 12 people? We all know that there are C(12,3) = 220 possibilities (C(N,K) denotes the<br />
well-known binomial coefficients). For pure mathematicians, this result may be great. But we want to really generate all the possibilities in a list.<br />
<br />
<pre><br />
Example:<br />
* (combinations 3 '(a b c d e f))<br />
((A B C) (A B D) (A B E) ... )<br />
<br />
Example in Haskell:<br />
> combinations 3 "abcdef"<br />
["abc","abd","abe",...]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
-- Import the 'tails' function<br />
-- > tails [0,1,2,3]<br />
-- [[0,1,2,3],[1,2,3],[2,3],[3],[]]<br />
import Data.List (tails)<br />
<br />
-- The implementation first checks if there's no more elements to select,<br />
-- if so, there's only one possible combination, the empty one,<br />
-- otherwise we need to select 'n' elements. Since we don't want to<br />
-- select an element twice, and we want to select elements in order, to<br />
-- avoid combinations which only differ in ordering, we skip some<br />
-- unspecified initial elements with 'tails', and select the next element,<br />
-- also recursively selecting the next 'n-1' element from the rest of the<br />
-- tail, finally consing them together<br />
<br />
-- Using list comprehensions<br />
combinations :: Int -> [a] -> [[a]]<br />
combinations 0 _ = [ [] ]<br />
combinations n xs = [ y:ys | y:xs' <- tails xs<br />
, ys <- combinations (n-1) xs']<br />
<br />
-- Alternate syntax, using 'do'-notation <br />
combinations :: Int -> [a] -> [[a]]<br />
combinations 0 _ = do return []<br />
combinations n xs = do y:xs' <- tails xs<br />
ys <- combinations (n-1) xs'<br />
return (y:ys)<br />
</haskell><br />
<br />
== Problem 27 ==<br />
<br />
Group the elements of a set into disjoint subsets.<br />
<br />
a) In how many ways can a group of 9 people work in 3 disjoint subgroups of 2, 3 and 4 persons? Write a function that generates all the possibilities and returns them in a list.<br />
<br />
<pre><br />
Example:<br />
* (group3 '(aldo beat carla david evi flip gary hugo ida))<br />
( ( (ALDO BEAT) (CARLA DAVID EVI) (FLIP GARY HUGO IDA) )<br />
... )<br />
</pre><br />
<br />
b) Generalize the above predicate in a way that we can specify a list of group sizes and the predicate will return a list of groups.<br />
<br />
<pre><br />
Example:<br />
* (group '(aldo beat carla david evi flip gary hugo ida) '(2 2 5))<br />
( ( (ALDO BEAT) (CARLA DAVID) (EVI FLIP GARY HUGO IDA) )<br />
... )<br />
</pre><br />
<br />
Note that we do not want permutations of the group members; i.e. ((ALDO BEAT) ...) is the same solution as ((BEAT ALDO) ...). However, we make a difference between ((ALDO BEAT) (CARLA DAVID) ...) and ((CARLA DAVID) (ALDO BEAT) ...).<br />
<br />
You may find more about this combinatorial problem in a good book on discrete mathematics under the term "multinomial coefficients".<br />
<br />
<pre><br />
Example in Haskell:<br />
<example in Haskell><br />
<br />
P27> group [2,3,4] ["aldo","beat","carla","david","evi","flip","gary","hugo","ida"]<br />
[[["aldo","beat"],["carla","david","evi"],["flip","gary","hugo","ida"]],...]<br />
(altogether 1260 solutions)<br />
<br />
27> group [2,2,5] ["aldo","beat","carla","david","evi","flip","gary","hugo","ida"]<br />
[[["aldo","beat"],["carla","david"],["evi","flip","gary","hugo","ida"]],...]<br />
(altogether 756 solutions)<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
combination :: Int -> [a] -> [([a],[a])]<br />
combination 0 xs = [([],xs)]<br />
combination n [] = []<br />
combination n (x:xs) = ts ++ ds<br />
where<br />
ts = [ (x:ys,zs) | (ys,zs) <- combination (n-1) xs ]<br />
ds = [ (ys,x:zs) | (ys,zs) <- combination n xs ]<br />
<br />
group :: [Int] -> [a] -> [[[a]]]<br />
group [] _ = [[]]<br />
group (n:ns) xs = do<br />
(g,rs) <- combination n xs<br />
gs <- group ns rs<br />
return $ g:gs<br />
</haskell><br />
<br />
First of all we acknowledge that we need something like <hask>combination</hask> from the above problem. Actually we need more than the elements we selected, we also need the elements we did not select. Therefore we cannot use the <hask>tails</hask> function because it throws too much information away. But in general this function works like the one above. In each step of the recursion we have to decide whether we want to take the first element of the list <hask>(x:xs)</hask> in the combination (we collect the possibilities for this choice in <hask>ts</hask>) or if we don't want it in the combination (<hask>ds</hask> collects the possibilities for this case).<br />
<br />
Now we need a function <hask>group</hask> that does the needed work. First we denote that if we don't want any group there is only one solution: a list of no groups. But if we want at least one group with n members we have to select n elements of <hask>xs</hask> into a group <hask>g</hask> and the remaining elements into <hask>rs</hask>. Afterwards we group those remaining elements, get a list of groups <hask>gs</hask> and prepend <hask>g</hask> as the first group.<br />
<br />
And a way for those who like it shorter (but less comprehensive):<br />
<haskell><br />
group :: [Int] -> [a] -> [[[a]]]<br />
group [] = const [[]]<br />
group (n:ns) = concatMap (uncurry $ (. group ns) . map . (:)) . combination n<br />
</haskell><br />
<br />
== Problem 28 ==<br />
<br />
Sorting a list of lists according to length of sublists<br />
<br />
a) We suppose that a list contains elements that are lists themselves. The objective is to sort the elements of this list according to their length. E.g. short lists first, longer lists later, or vice versa.<br />
<br />
<pre><br />
Example:<br />
* (lsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))<br />
((O) (D E) (D E) (M N) (A B C) (F G H) (I J K L))<br />
<br />
Example in Haskell:<br />
Prelude>lsort ["abc","de","fgh","de","ijkl","mn","o"]<br />
Prelude>["o","de","de","mn","abc","fgh","ijkl"]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
import List<br />
lsort :: [[a]]->[[a]]<br />
lsort = sortBy (\x y->compare (length x) (length y))<br />
</haskell><br />
<br />
This function also works for empty list. Import List to use sortBy.<br />
<br />
b) Again, we suppose that a list contains elements that are lists themselves. But this time the objective is to sort the elements of this list according to their <b>length frequency</b>; i.e., in the default, where sorting is done ascendingly, lists with rare lengths are placed first, others with a more frequent length come later.<br />
<br />
<pre><br />
Example:<br />
* (lfsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))<br />
((i j k l) (o) (a b c) (f g h) (d e) (d e) (m n))<br />
<br />
Example in Haskell:<br />
lfsort ["abc", "de", "fgh", "de", "ijkl", "mn", "o"]<br />
["ijkl","o","abc","fgh","de","de","mn"]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
import List<br />
comparing p x y = compare (p x) (p y)<br />
lfsort lists = sortBy (comparing frequency) lists where<br />
lengths = map length lists<br />
frequency list = length $ filter (== length list) lengths<br />
</haskell><br />
<br />
What we need is a function that takes a sublist and counts the number of other sublists with the same length. To do this, we first construct a list containing the lengths of all the sublists (called lengths above). Then the function frequency can just count the number of times that the current sublist's length occurs in lengths.<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=991299 questions/11 to 202007-01-05T06:07:21Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
rotate xs n = if n >= 0 then<br />
drop n xs ++ take n xs<br />
else let l = ((length xs) + n) in<br />
drop l xs ++ take l xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
or <br />
<br />
<haskell><br />
removeAt n xs = (xs!!n,take n xs ++ drop (n+1) xs)<br />
</haskell><br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=991199 questions/11 to 202007-01-05T06:02:32Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
rotate xs n = if n >= 0 then<br />
drop n xs ++ take n xs<br />
else let l = ((length xs) + n) in<br />
drop l xs ++ take l xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=991099 questions/11 to 202007-01-05T06:01:27Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
rotate xs n = if n >= 0 then<br />
drop n xs ++ take n xs<br />
else let l = ((length xs) + n) in<br />
drop l xs ++ take l xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=990999 questions/11 to 202007-01-05T05:58:34Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
rotate s n = if n >= 0 then<br />
drop n s ++ take n s<br />
else let l = ((length s) + n) in<br />
drop l s ++ take l s<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=990899 questions/11 to 202007-01-05T05:53:11Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
rotate n s = if n >= 0 then<br />
drop n s ++ take n s<br />
else let l = ((length s) + n) in<br />
drop l s ++ take l s<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=990799 questions/11 to 202007-01-05T05:31:53Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!(i-1)..xs!!(j-1)]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=990699 questions/11 to 202007-01-05T05:25:58Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or<br />
<br />
<haskell><br />
slice xs i j = [xs!!i..xs!!j]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=990599 questions/11 to 202007-01-05T05:25:22Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
or, using the <haskell>(!!)</haskell> operator:<br />
<br />
<haskell><br />
slice xs i j = [xs!!i..xs!!j]<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/11_to_20&diff=988599 questions/11 to 202007-01-04T05:55:51Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
== Problem 11 ==<br />
<br />
(*) Modified run-length encoding. <br />
Modify the result of problem 10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.<br />
<br />
<pre><br />
Example:<br />
* (encode-modified '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P11> encodeModified "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
data ListItem a = Single a | Multiple Int a<br />
deriving (Show)<br />
<br />
encodeModified :: Eq a => [a] -> [ListItem a]<br />
encodeModified = map encodeHelper . encode<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
Again, like in problem 7, we need a utility type because lists in haskell are homogeneous. Afterwards we use the <hask>encode</hask> function from problem 10 and map single instances of a list item to <hask>Single</hask> and multiple ones to <hask>Multiple</hask>.<br />
<br />
The ListItem definition contains 'deriving (Show)' so that we can get interactive output.<br />
<br />
== Problem 12 ==<br />
<br />
(**) Decode a run-length encoded list. <br />
Given a run-length code list generated as specified in problem 11. Construct its uncompressed version.<br />
<br />
<pre><br />
Example in Haskell:<br />
P12> decodeModified [Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
"aaaabccaadeeee"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
decodeModified :: [ListItem a] -> [a]<br />
decodeModified = concatMap decodeHelper<br />
where<br />
decodeHelper (Single x) = [x]<br />
decodeHelper (Multiple n x) = replicate n x<br />
</haskell><br />
<br />
We only need to map single instances of an element to a list containing only one element and multiple ones to a list containing the specified number of elements and concatenate these lists.<br />
<br />
== Problem 13 ==<br />
<br />
(**) Run-length encoding of a list (direct solution). <br />
Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem 9, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.<br />
<br />
<pre><br />
Example:<br />
* (encode-direct '(a a a a b c c a a d e e e e))<br />
((4 A) B (2 C) (2 A) D (4 E))<br />
<br />
Example in Haskell:<br />
P13> encodeDirect "aaaabccaadeeee"<br />
[Multiple 4 'a',Single 'b',Multiple 2 'c',Multiple 2 'a',Single 'd',Multiple 4 'e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode' :: Eq a => [a] -> [(Int,a)]<br />
encode' = foldr helper []<br />
where<br />
helper x [] = [(1,x)]<br />
helper x (y:ys)<br />
| x == snd y = (1+fst y,x):ys<br />
| otherwise = (1,x):y:ys<br />
<br />
encodeDirect :: Eq a => [a] -> [ListItem a]<br />
encodeDirect = map encodeHelper . encode'<br />
where<br />
encodeHelper (1,x) = Single x<br />
encodeHelper (n,x) = Multiple n x<br />
</haskell><br />
<br />
First of all we could rewrite the function <hask>encode</hask> from problem 10 in a way that is does not create the sublists. Thus, I decided to traverse the original list from right to left (using <hask>foldr</hask>) and to prepend each element to the resulting list in the proper way. Thereafter we only need to modify the function <hask>encodeModified</hask> from problem 11 to use <hask>encode'</hask>.<br />
<br />
== Problem 14 ==<br />
<br />
(*) Duplicate the elements of a list.<br />
<br />
<pre><br />
Example:<br />
* (dupli '(a b c c d))<br />
(A A B B C C C C D D)<br />
<br />
Example in Haskell:<br />
> dupli [1, 2, 3]<br />
[1,1,2,2,3,3]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
dupli [] = []<br />
dupli (x:xs) = x:x:dupli xs<br />
</haskell><br />
<br />
or, using list comprehension syntax:<br />
<br />
<haskell><br />
concat [[x,x]|x<-[1,2,3]]<br />
</haskell><br />
<br />
or, using the list monad:<br />
<haskell><br />
dupli xs = xs >>= (\x -> [x,x])<br />
</haskell><br />
<br />
== Problem 15 ==<br />
<br />
(**) Replicate the elements of a list a given number of times.<br />
<br />
<pre><br />
Example:<br />
* (repli '(a b c) 3)<br />
(A A A B B B C C C)<br />
<br />
Example in Haskell:<br />
> repli "abc" 3<br />
"aaabbbccc"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
repli :: [a] -> Int -> [a]<br />
repli xs n = concatMap (replicate n) xs<br />
</haskell><br />
<br />
== Problem 16 ==<br />
(**) Drop every N'th element from a list.<br />
<br />
<pre><br />
Example:<br />
* (drop '(a b c d e f g h i k) 3)<br />
(A B D E G H K)<br />
<br />
Example in Haskell:<br />
*Main> drop = "abcdefghik" 3<br />
"abdeghk"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
drop xs n = drops xs (n-1) n<br />
drops [] _ _ = []<br />
drops (x:xs) 0 max = drops xs (max-1) max<br />
drops (x:xs) (n+1) max = x:drops xs n max<br />
</haskell><br />
<br />
Here, drops is a helper-function to drop. In drops, there is an index n that counts from max-1 down to 0, and removes the head element each time it hits 0.<br />
<br />
Note that drop is one of the standard Haskell functions, so redefining it is generally not a good idea.<br />
<br />
or using zip:<br />
<haskell><br />
drop n = map snd . filter ((n/=) . fst) . zip (cycle [1..n])<br />
</haskell><br />
<br />
== Problem 17 ==<br />
<br />
(*) Split a list into two parts; the length of the first part is given.<br />
<br />
Do not use any predefined predicates.<br />
<br />
<pre><br />
Example:<br />
* (split '(a b c d e f g h i k) 3)<br />
( (A B C) (D E F G H I K))<br />
<br />
Example in Haskell:<br />
*Main> split "abcdefghik" 3<br />
("abc", "defghik")<br />
</pre><br />
<br />
Solution using take and drop:<br />
<haskell><br />
split xs n = (take n xs, drop n xs)<br />
</haskell><br />
Note that this function, with the parameters in the other order, exists as <hask>splitAt</hask>.<br />
<br />
<br />
== Problem 18 ==<br />
<br />
(**) Extract a slice from a list.<br />
<br />
Given two indices, i and k, the slice is the list containing the elements between the i'th and i'th element of the original list (both limits included). Start counting the elements with 1.<br />
<br />
<pre><br />
Example:<br />
* (slice '(a b c d e f g h i k) 3 7)<br />
(C D E F G)<br />
<br />
Example in Haskell:<br />
*Main> slice ['a','b','c','d','e','f','g','h','i','k'] 3 7<br />
"cdefg"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
slice xs (i+1) k = take (k-i) $ drop i xs<br />
</haskell><br />
<br />
== Problem 19 ==<br />
<br />
(**) Rotate a list N places to the left.<br />
<br />
Hint: Use the predefined functions length and (++).<br />
<br />
<pre><br />
Examples:<br />
* (rotate '(a b c d e f g h) 3)<br />
(D E F G H A B C)<br />
<br />
* (rotate '(a b c d e f g h) -2)<br />
(G H A B C D E F)<br />
<br />
Examples in Haskell:<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] 3<br />
"defghabc"<br />
<br />
*Main> rotate ['a','b','c','d','e','f','g','h'] (-2)<br />
"ghabcdef"<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
rotate [] _ = []<br />
rotate l 0 = l<br />
rotate (x:xs) (n+1) = rotate (xs ++ [x]) n<br />
rotate l n = rotate l (length l + n)<br />
</haskell><br />
<br />
There are two separate cases:<br />
* If n > 0, move the first element to the end of the list n times.<br />
* If n < 0, convert the problem to the equivalent problem for n > 0 by adding the list's length to n.<br />
<br />
or using cycle:<br />
<haskell><br />
rotate xs n = take len . drop (n `mod` len) . cycle $ xs<br />
where len = length xs<br />
</haskell><br />
<br />
== Problem 20 ==<br />
<br />
(*) Remove the K'th element from a list.<br />
<br />
Example in Prolog:<br />
<pre><br />
?- remove_at(X,[a,b,c,d],2,R).<br />
X = b<br />
R = [a,c,d]<br />
</pre><br />
<br />
Example in Lisp:<br />
<pre><br />
* (remove-at '(a b c d) 2)<br />
(A C D)<br />
</pre><br />
(Note that this only returns the residue list, while the Prolog version also returns the deleted element.)<br />
<br />
Example in Haskell:<br />
<pre><br />
*Main> removeAt 1 removeAt 1 "abcd"<br />
('b',"acd")<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
removeAt :: Int -> [a] -> (a, [a])<br />
removeAt k xs = case back of<br />
[] -> error "removeAt: index too large"<br />
x:rest -> (x, front ++ rest)<br />
where (front, back) = splitAt k xs<br />
</haskell><br />
<br />
Simply use the <hask>splitAt</hask> to split after k elements.<br />
If the original list has fewer than k+1 elements, the second list will be empty, and there will be no element to extract.<br />
Note that the Prolog and Lisp versions treat 1 as the first element in the list, and the Lisp version appends NIL elements to the end of the list if k is greater than the list length.<br />
<br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/1_to_10&diff=988499 questions/1 to 102007-01-04T04:43:34Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Problem 1 ==<br />
<br />
(*) Find the last box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-last '(a b c d))<br />
(D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myLast [1,2,3,4]<br />
[4]<br />
Prelude> myLast ['x','y','z']<br />
"z"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myLast :: [a] -> [a]<br />
myLast [x] = [x]<br />
myLast (_:xs) = myLast xs<br />
</haskell><br />
<br />
Haskell also provides the function <hask>last</hask>.<br />
<br />
== Problem 2 ==<br />
<br />
(*) Find the last but one box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-but-last '(a b c d))<br />
(C D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myButLast [1,2,3,4]<br />
[3,4]<br />
Prelude> myButLast ['a'..'z']<br />
"yz"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myButLast :: [a] -> [a]<br />
myButLast list = drop ((length list) - 2) list<br />
</haskell><br />
<br />
This simply drops all the but last two elements of a list.<br />
<br />
Some other options:<br />
<haskell><br />
myButLast = reverse . take 2 . reverse<br />
</haskell><br />
or<br />
<haskell><br />
myButLast = last . liftM2 (zipWith const) tails (drop 1)<br />
</haskell><br />
or<br />
<haskell><br />
myButLast [a, b] = [a, b]<br />
myButLast (_ : xs) = myButLast xs<br />
</haskell><br />
(I'm very new to Haskell but this last one definitely seems to work -- bakert.)<br />
<br />
Remark:<br />
The Lisp solution is actually wrong, it should not be the last two elements; a correct Haskell solution is:<br />
<haskell><br />
myButLast = last . init<br />
Prelude> myButLast ['a'..'z']<br />
'y'<br />
</haskell><br />
See also the solution to problem 2 in the Prolog list.<br />
<br />
== Problem 3 ==<br />
<br />
(*) Find the K'th element of a list. The first element in the list is number 1.<br />
<br />
Example:<br />
<br />
<pre><br />
* (element-at '(a b c d e) 3)<br />
C<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> elementAt [1,2,3] 2<br />
2<br />
Prelude> elementAt "haskell" 5<br />
'e'<br />
</haskell><br />
<br />
Solution:<br />
<br />
This is (almost) the infix operator !! in Prelude, which is defined as:<br />
<br />
<haskell><br />
(!!) :: [a] -> Int -> a<br />
(x:_) !! 0 = x<br />
(_:xs) !! n = xs !! (n-1)<br />
</haskell><br />
<br />
Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So:<br />
<br />
<haskell><br />
elementAt :: [a] -> Int -> a<br />
elementAt list i = list !! (i-1)<br />
</haskell><br />
<br />
== Problem 4 ==<br />
<br />
(*) Find the number of elements of a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> length [123, 456, 789]<br />
3<br />
Prelude> length "Hello, world!"<br />
13<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
length :: [a] -> Int<br />
length [] = 0<br />
length (_:l) = 1 + length l<br />
</haskell><br />
<br />
This function is defined in Prelude.<br />
<br />
== Problem 5 ==<br />
<br />
(*) Reverse a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> reverse "A man, a plan, a canal, panama!"<br />
"!amanap ,lanac a ,nalp a ,nam A"<br />
Prelude> reverse [1,2,3,4]<br />
[4,3,2,1]<br />
</haskell><br />
<br />
Solution: (defined in Prelude)<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse = foldl (flip (:)) []<br />
</haskell><br />
<br />
The standard definition is concise, but not very readable. Another way to define reverse is:<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse [] = []<br />
reverse (x:xs) = reverse xs ++ [x]<br />
</haskell><br />
<br />
== Problem 6 ==<br />
<br />
(*) Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> isPalindrome [1,2,3]<br />
False<br />
*Main> isPalindrome "madamimadam"<br />
True<br />
*Main> isPalindrome [1,2,4,8,16,8,4,2,1]<br />
True<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
isPalindrome :: (Eq a) => [a] -> Bool<br />
isPalindrome xs = xs == (reverse xs)<br />
</haskell><br />
<br />
== Problem 7 ==<br />
<br />
(**) Flatten a nested list structure.<br />
<br />
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-flatten '(a (b (c d) e)))<br />
(A B C D E)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> flatten (Elem 5)<br />
[5]<br />
*Main> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])<br />
[1,2,3,4,5]<br />
*Main> flatten (List [])<br />
[]<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
data NestedList a = Elem a | List [NestedList a]<br />
<br />
flatten :: NestedList a -> [a]<br />
flatten (Elem x) = [x]<br />
flatten (List x) = concatMap flatten x<br />
</haskell><br />
<br />
We have to define a new data type, because lists in Haskell are homogeneous.<br />
[1, [2, [3, 4], 5]] is a type error. Therefore, we must have a way of<br />
representing a list that may (or may not) be nested.<br />
<br />
Our NestedList datatype is either a single element of some type (Elem a), or a<br />
list of NestedLists of the same type. (List [NestedList a]). <br />
<br />
== Problem 8 ==<br />
<br />
(**) Eliminate consecutive duplicates of list elements.<br />
<br />
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.<br />
<br />
<pre><br />
Example:<br />
* (compress '(a a a a b c c a a d e e e e))<br />
(A B C A D E)<br />
<br />
Example in Haskell:<br />
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e']<br />
['a','b','c','a','d','e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
compress :: Eq a => [a] -> [a]<br />
compress = map head . group<br />
</haskell><br />
<br />
We simply group equal values together (group), then take the head of each. <br />
Note that (with GHC) we must give an explicit type to ''compress'' otherwise we get:<br />
<br />
<haskell><br />
Ambiguous type variable `a' in the constraint:<br />
`Eq a'<br />
arising from use of `group' <br />
Possible cause: the monomorphism restriction applied to the following:<br />
compress :: [a] -> [a]<br />
Probable fix: give these definition(s) an explicit type signature<br />
or use -fno-monomorphism-restriction<br />
</haskell><br />
<br />
We can circumvent the monomorphism restriction by writing ''compress'' this way (See: section 4.5.4 of [http://haskell.org/onlinereport the report]):<br />
<br />
<haskell>compress xs = map head $ group xs</haskell><br />
<br />
An alternative solution is<br />
<br />
<haskell><br />
compress [] = []<br />
compress [a] = [a]<br />
compress (x : y : xs) = (if x == y then [] else [x]) ++ compress (y : xs)<br />
</haskell><br />
<br />
Another alternative is to use the Data.Set module to construct a Set. This solution also works if the repeated elements are not consecutive. This solution is potentially incorrect in the spirit of this quiz as it creates a data structure of a new type (Set), but still addresses the problem in question.<br />
<br />
<pre><br />
Prelude> let r = ["a","a","b","b","c","c","c"]<br />
Prelude> :m Data.Set<br />
Prelude Data.Set> let s = fromList r<br />
Prelude Data.Set> s<br />
fromList ["a","b","c"]<br />
</pre><br />
<br />
== Problem 9 ==<br />
<br />
(**) Pack consecutive duplicates of list elements into sublists.<br />
If a list contains repeated elements they should be placed in separate sublists.<br />
<br />
<pre><br />
Example:<br />
* (pack '(a a a a b c c a a d e e e e))<br />
((A A A A) (B) (C C) (A A) (D) (E E E E))<br />
<example in lisp><br />
<br />
Example in Haskell:<br />
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']<br />
["aaaa","b","cc","aa","d","eeee"]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
pack (x:xs) = let (first,rest) = span (==x) xs<br />
in (x:first) : pack rest<br />
pack [] = []<br />
</haskell><br />
<br />
'group' is also in the Prelude, here's an implementation using 'span'.<br />
<br />
== Problem 10 ==<br />
<br />
(*) Run-length encoding of a list.<br />
Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.<br />
<br />
Example:<br />
<pre><br />
* (encode '(a a a a b c c a a d e e e e))<br />
((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
encode "aaaabccaadeeee"<br />
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode xs = map (\x -> (length x,head x)) (group xs)<br />
</haskell><br />
<br />
which can also be expressed as a list comprehension:<br />
<br />
<haskell><br />
[(length x, head x) | x <- group xs]<br />
</haskell><br />
<br />
Or writing it [[Pointfree]]:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode = map (\x -> (length x, head x)) . group<br />
</haskell><br />
<br />
Or (ab)using the "&&&" arrow operator for tuples:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode xs = map (length &&& head) $ group xs<br />
</haskell><br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/1_to_10&diff=988399 questions/1 to 102007-01-04T04:43:02Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Problem 1 ==<br />
<br />
(*) Find the last box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-last '(a b c d))<br />
(D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myLast [1,2,3,4]<br />
[4]<br />
Prelude> myLast ['x','y','z']<br />
"z"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myLast :: [a] -> [a]<br />
myLast [x] = [x]<br />
myLast (_:xs) = myLast xs<br />
</haskell><br />
<br />
Haskell also provides the function <hask>last</hask>.<br />
<br />
== Problem 2 ==<br />
<br />
(*) Find the last but one box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-but-last '(a b c d))<br />
(C D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myButLast [1,2,3,4]<br />
[3,4]<br />
Prelude> myButLast ['a'..'z']<br />
"yz"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myButLast :: [a] -> [a]<br />
myButLast list = drop ((length list) - 2) list<br />
</haskell><br />
<br />
This simply drops all the but last two elements of a list.<br />
<br />
Some other options:<br />
<haskell><br />
myButLast = reverse . take 2 . reverse<br />
</haskell><br />
or<br />
<haskell><br />
myButLast = last . liftM2 (zipWith const) tails (drop 1)<br />
</haskell><br />
or<br />
<haskell><br />
myButLast [a, b] = [a, b]<br />
myButLast (_ : xs) = myButLast xs<br />
</haskell><br />
(I'm very new to Haskell but this last one definitely seems to work -- bakert.)<br />
<br />
Remark:<br />
The Lisp solution is actually wrong, it should not be the last two elements; a correct Haskell solution is:<br />
<haskell><br />
myButLast = last . init<br />
Prelude> myButLast ['a'..'z']<br />
'y'<br />
</haskell><br />
See also the solution to problem 2 in the Prolog list.<br />
<br />
== Problem 3 ==<br />
<br />
(*) Find the K'th element of a list. The first element in the list is number 1.<br />
<br />
Example:<br />
<br />
<pre><br />
* (element-at '(a b c d e) 3)<br />
C<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> elementAt [1,2,3] 2<br />
2<br />
Prelude> elementAt "haskell" 5<br />
'e'<br />
</haskell><br />
<br />
Solution:<br />
<br />
This is (almost) the infix operator !! in Prelude, which is defined as:<br />
<br />
<haskell><br />
(!!) :: [a] -> Int -> a<br />
(x:_) !! 0 = x<br />
(_:xs) !! n = xs !! (n-1)<br />
</haskell><br />
<br />
Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So:<br />
<br />
<haskell><br />
elementAt :: [a] -> Int -> a<br />
elementAt list i = list !! (i-1)<br />
</haskell><br />
<br />
== Problem 4 ==<br />
<br />
(*) Find the number of elements of a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> length [123, 456, 789]<br />
3<br />
Prelude> length "Hello, world!"<br />
13<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
length :: [a] -> Int<br />
length [] = 0<br />
length (_:l) = 1 + length l<br />
</haskell><br />
<br />
This function is defined in Prelude.<br />
<br />
== Problem 5 ==<br />
<br />
(*) Reverse a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> reverse "A man, a plan, a canal, panama!"<br />
"!amanap ,lanac a ,nalp a ,nam A"<br />
Prelude> reverse [1,2,3,4]<br />
[4,3,2,1]<br />
</haskell><br />
<br />
Solution: (defined in Prelude)<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse = foldl (flip (:)) []<br />
</haskell><br />
<br />
The standard definition is concise, but not very readable. Another way to define reverse is:<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse [] = []<br />
reverse (x:xs) = reverse xs ++ [x]<br />
</haskell><br />
<br />
== Problem 6 ==<br />
<br />
(*) Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> isPalindrome [1,2,3]<br />
False<br />
*Main> isPalindrome "madamimadam"<br />
True<br />
*Main> isPalindrome [1,2,4,8,16,8,4,2,1]<br />
True<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
isPalindrome :: (Eq a) => [a] -> Bool<br />
isPalindrome xs = xs == (reverse xs)<br />
</haskell><br />
<br />
== Problem 7 ==<br />
<br />
(**) Flatten a nested list structure.<br />
<br />
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-flatten '(a (b (c d) e)))<br />
(A B C D E)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> flatten (Elem 5)<br />
[5]<br />
*Main> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])<br />
[1,2,3,4,5]<br />
*Main> flatten (List [])<br />
[]<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
data NestedList a = Elem a | List [NestedList a]<br />
<br />
flatten :: NestedList a -> [a]<br />
flatten (Elem x) = [x]<br />
flatten (List x) = concatMap flatten x<br />
</haskell><br />
<br />
We have to define a new data type, because lists in Haskell are homogeneous.<br />
[1, [2, [3, 4], 5]] is a type error. Therefore, we must have a way of<br />
representing a list that may (or may not) be nested.<br />
<br />
Our NestedList datatype is either a single element of some type (Elem a), or a<br />
list of NestedLists of the same type. (List [NestedList a]). <br />
<br />
== Problem 8 ==<br />
<br />
(**) Eliminate consecutive duplicates of list elements.<br />
<br />
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.<br />
<br />
<pre><br />
Example:<br />
* (compress '(a a a a b c c a a d e e e e))<br />
(A B C A D E)<br />
<br />
Example in Haskell:<br />
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e']<br />
['a','b','c','a','d','e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
compress :: Eq a => [a] -> [a]<br />
compress = map head . group<br />
</haskell><br />
<br />
We simply group equal values together (group), then take the head of each. <br />
Note that (with GHC) we must give an explicit type to ''compress'' otherwise we get:<br />
<br />
<haskell><br />
Ambiguous type variable `a' in the constraint:<br />
`Eq a'<br />
arising from use of `group' <br />
Possible cause: the monomorphism restriction applied to the following:<br />
compress :: [a] -> [a]<br />
Probable fix: give these definition(s) an explicit type signature<br />
or use -fno-monomorphism-restriction<br />
</haskell><br />
<br />
We can circumvent the monomorphism restriction by writing ''compress'' this way (See: section 4.5.4 of [http://haskell.org/onlinereport the report]):<br />
<br />
<haskell>compress xs = map head $ group xs</haskell><br />
<br />
An alternative solution is<br />
<br />
<haskell><br />
compress [] = []<br />
compress [a] = [a]<br />
compress (x : y : xs) = (if x == y then [] else [x]) ++ compress (y : xs)<br />
</haskell><br />
<br />
Another alternative is to use the Data.Set module to construct a Set. This solution also works if the repeated elements are not consecutive. This solution is potentially incorrect in the spirit of this quiz as it creates a data structure of a new type (Set), but still addresses the problem in question.<br />
<br />
<pre><br />
Prelude> let r = ["a","a","b","b","c","c","c"]<br />
Prelude> :m Data.Set<br />
Prelude Data.Set> let s = fromList r<br />
Prelude Data.Set> s<br />
fromList ["a","b","c"]<br />
</pre><br />
<br />
== Problem 9 ==<br />
<br />
(**) Pack consecutive duplicates of list elements into sublists.<br />
If a list contains repeated elements they should be placed in separate sublists.<br />
<br />
<pre><br />
Example:<br />
* (pack '(a a a a b c c a a d e e e e))<br />
((A A A A) (B) (C C) (A A) (D) (E E E E))<br />
<example in lisp><br />
<br />
Example in Haskell:<br />
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']<br />
["aaaa","b","cc","aa","d","eeee"]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
pack (x:xs) = let (first,rest) = span (==x) xs<br />
in (x:first) : pack rest<br />
pack [] = []<br />
</haskell><br />
<br />
'group' is also in the Prelude, here's an implementation using 'span'.<br />
<br />
== Problem 10 ==<br />
<br />
(*) Run-length encoding of a list.<br />
Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.<br />
<br />
Example:<br />
<pre><br />
* (encode '(a a a a b c c a a d e e e e))<br />
((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
encode "aaaabccaadeeee"<br />
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode xs = map (\x -> (length x,head x)) (group xs)<br />
</haskell><br />
<br />
which can also be expressed as a list comprehension:<br />
<br />
[(length x, head x) | x <- group xs]<br />
<br />
Or writing it [[Pointfree]]:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode = map (\x -> (length x, head x)) . group<br />
</haskell><br />
<br />
Or (ab)using the "&&&" arrow operator for tuples:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode xs = map (length &&& head) $ group xs<br />
</haskell><br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=99_questions/1_to_10&diff=987199 questions/1 to 102007-01-03T06:08:21Z<p>B7j0c: </p>
<hr />
<div>__NOTOC__<br />
<br />
This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [http://www.hta-bi.bfh.ch/~hew/informatik3/prolog/p-99/ Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html Ninety-Nine Lisp Problems].<br />
<br />
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields. <br />
<br />
== Problem 1 ==<br />
<br />
(*) Find the last box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-last '(a b c d))<br />
(D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myLast [1,2,3,4]<br />
[4]<br />
Prelude> myLast ['x','y','z']<br />
"z"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myLast :: [a] -> [a]<br />
myLast [x] = [x]<br />
myLast (_:xs) = myLast xs<br />
</haskell><br />
<br />
Haskell also provides the function <hask>last</hask>.<br />
<br />
== Problem 2 ==<br />
<br />
(*) Find the last but one box of a list.<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-but-last '(a b c d))<br />
(C D)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> myButLast [1,2,3,4]<br />
[3,4]<br />
Prelude> myButLast ['a'..'z']<br />
"yz"<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
myButLast :: [a] -> [a]<br />
myButLast list = drop ((length list) - 2) list<br />
</haskell><br />
<br />
This simply drops all the but last two elements of a list.<br />
<br />
Some other options:<br />
<haskell><br />
myButLast = reverse . take 2 . reverse<br />
</haskell><br />
or<br />
<haskell><br />
myButLast = last . liftM2 (zipWith const) tails (drop 1)<br />
</haskell><br />
or<br />
<haskell><br />
myButLast [a, b] = [a, b]<br />
myButLast (_ : xs) = myButLast xs<br />
</haskell><br />
(I'm very new to Haskell but this last one definitely seems to work -- bakert.)<br />
<br />
Remark:<br />
The Lisp solution is actually wrong, it should not be the last two elements; a correct Haskell solution is:<br />
<haskell><br />
myButLast = last . init<br />
Prelude> myButLast ['a'..'z']<br />
'y'<br />
</haskell><br />
See also the solution to problem 2 in the Prolog list.<br />
<br />
== Problem 3 ==<br />
<br />
(*) Find the K'th element of a list. The first element in the list is number 1.<br />
<br />
Example:<br />
<br />
<pre><br />
* (element-at '(a b c d e) 3)<br />
C<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> elementAt [1,2,3] 2<br />
2<br />
Prelude> elementAt "haskell" 5<br />
'e'<br />
</haskell><br />
<br />
Solution:<br />
<br />
This is (almost) the infix operator !! in Prelude, which is defined as:<br />
<br />
<haskell><br />
(!!) :: [a] -> Int -> a<br />
(x:_) !! 0 = x<br />
(_:xs) !! n = xs !! (n-1)<br />
</haskell><br />
<br />
Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So:<br />
<br />
<haskell><br />
elementAt :: [a] -> Int -> a<br />
elementAt list i = list !! (i-1)<br />
</haskell><br />
<br />
== Problem 4 ==<br />
<br />
(*) Find the number of elements of a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> length [123, 456, 789]<br />
3<br />
Prelude> length "Hello, world!"<br />
13<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
length :: [a] -> Int<br />
length [] = 0<br />
length (_:l) = 1 + length l<br />
</haskell><br />
<br />
This function is defined in Prelude.<br />
<br />
== Problem 5 ==<br />
<br />
(*) Reverse a list.<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
Prelude> reverse "A man, a plan, a canal, panama!"<br />
"!amanap ,lanac a ,nalp a ,nam A"<br />
Prelude> reverse [1,2,3,4]<br />
[4,3,2,1]<br />
</haskell><br />
<br />
Solution: (defined in Prelude)<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse = foldl (flip (:)) []<br />
</haskell><br />
<br />
The standard definition is concise, but not very readable. Another way to define reverse is:<br />
<br />
<haskell><br />
reverse :: [a] -> [a]<br />
reverse [] = []<br />
reverse (x:xs) = reverse xs ++ [x]<br />
</haskell><br />
<br />
== Problem 6 ==<br />
<br />
(*) Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).<br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> isPalindrome [1,2,3]<br />
False<br />
*Main> isPalindrome "madamimadam"<br />
True<br />
*Main> isPalindrome [1,2,4,8,16,8,4,2,1]<br />
True<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
isPalindrome :: (Eq a) => [a] -> Bool<br />
isPalindrome xs = xs == (reverse xs)<br />
</haskell><br />
<br />
== Problem 7 ==<br />
<br />
(**) Flatten a nested list structure.<br />
<br />
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).<br />
<br />
Example:<br />
<br />
<pre><br />
* (my-flatten '(a (b (c d) e)))<br />
(A B C D E)<br />
</pre><br />
<br />
Example in Haskell:<br />
<br />
<haskell><br />
*Main> flatten (Elem 5)<br />
[5]<br />
*Main> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])<br />
[1,2,3,4,5]<br />
*Main> flatten (List [])<br />
[]<br />
</haskell><br />
<br />
Solution:<br />
<br />
<haskell><br />
data NestedList a = Elem a | List [NestedList a]<br />
<br />
flatten :: NestedList a -> [a]<br />
flatten (Elem x) = [x]<br />
flatten (List x) = concatMap flatten x<br />
</haskell><br />
<br />
We have to define a new data type, because lists in Haskell are homogeneous.<br />
[1, [2, [3, 4], 5]] is a type error. Therefore, we must have a way of<br />
representing a list that may (or may not) be nested.<br />
<br />
Our NestedList datatype is either a single element of some type (Elem a), or a<br />
list of NestedLists of the same type. (List [NestedList a]). <br />
<br />
== Problem 8 ==<br />
<br />
(**) Eliminate consecutive duplicates of list elements.<br />
<br />
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.<br />
<br />
<pre><br />
Example:<br />
* (compress '(a a a a b c c a a d e e e e))<br />
(A B C A D E)<br />
<br />
Example in Haskell:<br />
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e']<br />
['a','b','c','a','d','e']<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
compress :: Eq a => [a] -> [a]<br />
compress = map head . group<br />
</haskell><br />
<br />
We simply group equal values together (group), then take the head of each. <br />
Note that (with GHC) we must give an explicit type to ''compress'' otherwise we get:<br />
<br />
<haskell><br />
Ambiguous type variable `a' in the constraint:<br />
`Eq a'<br />
arising from use of `group' <br />
Possible cause: the monomorphism restriction applied to the following:<br />
compress :: [a] -> [a]<br />
Probable fix: give these definition(s) an explicit type signature<br />
or use -fno-monomorphism-restriction<br />
</haskell><br />
<br />
We can circumvent the monomorphism restriction by writing ''compress'' this way (See: section 4.5.4 of [http://haskell.org/onlinereport the report]):<br />
<br />
<haskell>compress xs = map head $ group xs</haskell><br />
<br />
An alternative solution is<br />
<br />
<haskell><br />
compress [] = []<br />
compress [a] = [a]<br />
compress (x : y : xs) = (if x == y then [] else [x]) ++ compress (y : xs)<br />
</haskell><br />
<br />
Another alternative is to use the Data.Set module to construct a Set. This solution also works if the repeated elements are not consecutive. This solution is potentially incorrect in the spirit of this quiz as it creates a data structure of a new type (Set), but still addresses the problem in question.<br />
<br />
<pre><br />
Prelude> let r = ["a","a","b","b","c","c","c"]<br />
Prelude> :m Data.Set<br />
Prelude Data.Set> let s = fromList r<br />
Prelude Data.Set> s<br />
fromList ["a","b","c"]<br />
</pre><br />
<br />
== Problem 9 ==<br />
<br />
(**) Pack consecutive duplicates of list elements into sublists.<br />
If a list contains repeated elements they should be placed in separate sublists.<br />
<br />
<pre><br />
Example:<br />
* (pack '(a a a a b c c a a d e e e e))<br />
((A A A A) (B) (C C) (A A) (D) (E E E E))<br />
<example in lisp><br />
<br />
Example in Haskell:<br />
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']<br />
["aaaa","b","cc","aa","d","eeee"]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
pack (x:xs) = let (first,rest) = span (==x) xs<br />
in (x:first) : pack rest<br />
pack [] = []<br />
</haskell><br />
<br />
'group' is also in the Prelude, here's an implementation using 'span'.<br />
<br />
== Problem 10 ==<br />
<br />
(*) Run-length encoding of a list.<br />
Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.<br />
<br />
Example:<br />
<pre><br />
* (encode '(a a a a b c c a a d e e e e))<br />
((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))<br />
</pre><br />
<br />
Example in Haskell:<br />
<pre><br />
encode "aaaabccaadeeee"<br />
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]<br />
</pre><br />
<br />
Solution:<br />
<haskell><br />
encode xs = map (\x -> (length x,head x)) (group xs)<br />
</haskell><br />
<br />
Or writing it [[Pointfree]]:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode = map (\x -> (length x, head x)) . group<br />
</haskell><br />
<br />
Or (ab)using the "&&&" arrow operator for tuples:<br />
<br />
<haskell><br />
encode :: Eq a => [a] -> [(Int, a)]<br />
encode xs = map (length &&& head) $ group xs<br />
</haskell> <br />
[[Category:Tutorials]]</div>B7j0chttps://wiki.haskell.org/index.php?title=Wanted_libraries&diff=9028Wanted libraries2006-12-11T04:00:50Z<p>B7j0c: </p>
<hr />
<div>This page provides a list of missing and found libraries for solving<br />
common ''real world'' programmer tasks.<br />
<br />
If you think there should be a library for some common task, add it to<br />
this page, and someone may well step up and write it. If you know of a<br />
library to solve an open problem domain, link to it.<br />
<br />
The first place to look is [[Libraries_and_tools|the full libraries list]].<br />
<br />
<br />
== Missing libraries (by problem domain) ==<br />
<br />
Add any common problem areas for which libraries are missing.<br />
<br />
== Could be improved ==<br />
<br />
Problems with existing solutions, that could be improved.<br />
<br />
* The core HTTP libraries need a lot of work. There is the beginnings of a useful library there, but many http codes are not handled, and there should be simple 'get' and 'head' functionality. <br />
* Binary serialisation support should be ported to bytestring, and added to the extralibs bundle<br />
* Simple process forking/popen, of type <hask>String -> IO String</hask>, is needed (the implementation should be in base)<br />
<br />
If you have code that improves on something in the base libraries, you might consider [[Library_submissions|submitting it to the libraries process]], so it can appear in the standard libraries.<br />
<br />
== Existing libraries (by problem domain) ==<br />
<br />
See [[Libraries_and_tools|the full libraries list]].<br />
<br />
=== GUIs ===<br />
<br />
See [[Libraries_and_tools/GUI_libraries|GUI libraries]]<br />
<br />
=== High performance string IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Strings|String libraries]]<br />
<br />
=== Binary IO ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Serialising_data|Binary IO]]<br />
<br />
=== Compression ===<br />
<br />
See [[Libraries_and_tools/Data_structures#Compressing_data|Compressing data]]<br />
<br />
=== Encryption ===<br />
<br />
See [[Libraries_and_tools/Cryptography|Crypto libraries]]<br />
<br />
=== Web frameworks ===<br />
<br />
See [[Libraries_and_tools/Web_programming#Web_frameworks|Web frameworks]]<br />
<br />
=== XML processing ===<br />
<br />
See [[Libraries_and_tools/Web_programming#XML|XML handling]]<br />
<br />
=== Database access ===<br />
<br />
See [[Libraries_and_tools/Database_interfaces|Databases]]<br />
<br />
<br />
Add more problem domains that you feel we need libraries for!</div>B7j0c