Cogs and Levers A blog full of technical stuff

Practical Arrow Usage

Introduction

Arrows provide you with a way to represent computation. They provide some interesting compositional combinations for building more complex operations that you’re not going to find for Monads.

The Arrow Class is defined in the base libraries and can be imported from Control.Arrows. From Haskell.org’s Arrow page:

Arrows are a new abstract view of computation, defined by John Hughes [Hug00]. They serve much the same purpose as monads – providing a common structure for libraries – but are more general. In particular they allow notions of computation that may be partially static (independent of the input) or may take multiple inputs. If your application works fine with monads, you might as well stick with them. But if you’re using a structure that’s very like a monad, but isn’t one, maybe it’s an arrow.

Some interesting links on the topic follow:

If you’re interested in learning the theory behind Arrows or want to gain a deeper insight, I strongly suggest that you read through the above links.

Today’s post is going to take you through Arrows in practice when working in Haskell.

returnA

returnA gives you the identity arrow. It’s what you use in place of return that you would use in monadic contexts.

λ> :t returnA
returnA :: Arrow a => a b b
λ> :t returnA 5
returnA 5 :: Num b => b

arr

arr will take an ordinary function and make an arrow out of it.

λ> let a1 = arr (+)
λ> :t a1
a1 :: (Arrow a, Num b) => a b (b -> b)

Invoking your arrow is simple now with returnA and arr.

λ> a1 (returnA 5) 6
11

»>

»> performs left to right composition on arrows. This is very similar to what »= provides for monads.

λ> let a1 = arr (+5)
λ> let a2 = arr (*2)
λ> a1 >>> a2 $ 3
16

The next few functions that I’ll list here will work on pairs of values. This is where arrows really start to pull away from monads in terms of compositional capability. For example’s sake, I’ve defined q as a simple pair of integers:

λ> let q = (1,2)

first

first feeds the first element of a pair into the arrow for processing and leaves the second item untouched.

λ> first a1 q
(6,2)

second

second feeds the second element, but leaves the first untouched.

λ> second a1 q
(1,7)

***

*** will feed the first element of a pair through the first arrow, the second element will go through the second arrow. In the example below, the value 1 goes through the arrow a1 and 2 goes through a2.

λ> a1 *** a2 $ q
(6,4)

&&&

&&& will duplicate the input given to it and feed a copy to each arrow, returning a pair.

λ> a1 &&& a2 $ 5
(10,10)

proc

proc (arrow abstraction) builds a lambda that constructs an arrow as opposed to a function. proc allows you to build expressions (or arrows) using arrow notation.

{-# Language Arrows #-}

import Control.Arrow

addA :: Arrow a => a b Int -> a b Int -> a b Int
addA f g = proc x -> do
            y <- f -< x
            z <- g -< x
            returnA -< y + z

In this example, the type signature for addA is asking for two arrows from b to Int (a b Int) and will return an arrow of the same type.

The proc block has a lambda variable of x which is applied when the arrow is invoked. Remember, we’re only constructing an arrow here - not running it (yet).

The following lines make use of a new operator -< (arrow application). It feeds the value of an expression into an arrow. I think it helps to look at it like this:

variable binding pattern <- arrow -< pure expression giving arrow input

Invoking addA is done like so:

λ> let a1 = arr (+4)
λ> addA a1 a1 (returnA 3)
14

Here we have our arrow a1 that is just (+4). a1 is being supplied as the first and second parameter of addA. Lastly, we give addA our pure value returnA 3.

So, you can see here that (+4) has been applied to 3, and then (+4) gets applied to 3. Yes, I said the same thing twice. It’s only because I’ve used a1 as both input parameters. The output of these arrow invocations is then added together, to give the result of 14. Our pure value is being supplied by returnA 3.

These have just been some very fundamental examples of arrow usage. Read up some more on them using the links I’ve provided above. You can see how they’re quite a powerful construct.

Developing Window Managers

I wanted to use this post to jot down a few notes and resources for developing window managers for the X Windows system.

Tools

Tutorials and Manuals

Examples

Emacs Cheatsheet

Today’s post isn’t quite a normal post. I’m going to use this as a place to put all of my notes while using emacs.

Key Description
C-v Page down
M-v Page up
C-l Move text around the cursor (center, top, bottom)
C-p Previous line
C-n Next line
C-b Backwards character
C-f Forward character
M-b Backwards word
M-f Forward word
C-a Beginning of line
C-e End of line
M-a Beginning of sentence
M-e End of sentence
M-< Beginning of text
M-> End of text

Editing

Key Description
<DEL> Delete character before cursor
C-d Delete character after cursor
M-<DEL> Kill word before cursor
M-d Kill word after cursor
C-k Kill from cursor to EOL
M-k Kill to the end of current sentence
C-<SPC> Start selecting text
C-x h Select the whole buffer
C-w Kill selection
M-w Save region but don’t kill it
C-y Yank killed text
M-y Cycle through previous kills
C-/ Undo

Utility

Key Description
C-g Exit current command
C-u Repeat command
M-x replace-string Find and replace
M-x recover-file Recover file backup
C-M-\ Indent selected region

Files and Buffers

Key Description
C-x C-f Find a file (for opening)
C-x C-s Save current file
C-x C-b List buffers
C-x b Switch to a buffer
C-x s Save some buffers
C-x C-c Quit emacs (prompt for saves)
C-x k Kill buffer

Windows and Frames

Key Description
C-x 1 Delete all but current window
C-x 2 Split window horizontally
C-x 3 Split window verticaly
C-x 4 C-f Find a file into a new window
C-x o Move to other window
C-M-v Scroll bottom window
M-x make-frame Create a new emacs frame
M-x delete-frame Remove the selected emacs frame

Modes

Key Description
M-x fundamental-mode Fundamental
M-x text-mode Human text mode

Help

Key Description
C-h m Documentation on current major mode
C-h ? Get help on what you can get help on
C-h c Get help on a command
C-h f Get help on a function
C-h a List commands by keyword
C-h i Open manuals (open info buffer)

Searching

Key Description
C-s Start forward incremental search
C-r Start backward incremental search

When searching forwards, C-s will take you through all of the occurences of the search term that has been found. <DEL> takes you backwards. <DEL> starts to effect the search term once you’ve reached the first result.

Dired

Key Description
M-x dired Open dired in a buffer
o Open the highlighted file in the other buffer
C-o Open the file but keep focus in the dired buffer

unqualified host name; sleeping for retry

After a fresh installation of FreeBSD today, I’d noticed that my boot up time was suffering due to this message which consistently appears:

Jul 19 16:58:38 freebsd sm-mta[1097]: My unqualified host name (freebsd) unknown; sleeping for retry
Jul 19 16:59:38 freebsd sm-mta[1097]: unable to qualify my own domain name (freebsd) -- using short name
Jul 19 16:59:38 freebsd sm-msp-queue[1100]: My unqualified host name (freebsd) unknown; sleeping for retry
Jul 19 17:00:38 freebsd sm-msp-queue[1100]: unable to qualify my own domain name (freebsd) -- using short 

As you can see, this machine that I’ve created does have the very original hostname of freebsd.

What the error message is telling us is that I need to fully qualify my hostname. Editing /etc/rc.conf you can change the hostname value to include this information. The top line of my rc.conf now reads as follows:

hostname="freebsd.home"

No more slow boot times; because of this problem, at least.

Mounting remote filesystems with sshfs

Getting direct access over ssh is simplified greatly by sshfs, a fuse based file system. To get started, install sshfs with your favourite package manager:

$ sudo pacman -S sshfs

To connect to a remote file system, you just use the following:

$ sshfs host: mountpoint

Much like ssh, the host argument can take on the format of user@host if you’re logged in as a user that doesn’t correspond to the remote machine.

When you’re done, unmounting the filesystem is done like so:

$ fusermount -u mountpoint