Wishful Coding

Didn't you ever wish your
computer understood you?

Warning for changes in Arch

I’m using Arch on my new laptop because of problems with Fedora. But one problem with Arch linux is that it sometimes requires manual intervention when updating. If you don’t pay attention, this command might break your system.

pacman -Syu

The solution of course is to diligently check archlinux.org/news for breaking changes. But I obviously forget that all the time. If I have time at all.

Thinking this over, I was reminded of an annoying feature in OS X where if a cron job produced output, it would put that output in an mbox file. As long as you don’t clean up that file, every new terminal will say “You have new mail.” at the top.

Wouldn’t it be great if every new terminal would warn you about upgrading? Wish no more. I did exactly that with a few small scripts.

The first is a script that downloads the Arch RSS feed to a mbox, added to my crontab.

sudo systemctl enable cronie
crontab -e
0 * * * * /home/pepijn/bin/archheadline.py
#!/usr/bin/env python
import feedparser
from email.mime.text import MIMEText
from mailbox import mbox, mboxMessage

feed = feedparser.parse("https://www.archlinux.org/feeds/news/")
mail = mbox('/var/spool/mail/news')
ids = set([m['Message-ID'] for m in mail])

for entry in feed.entries:
    if entry.id not in ids:
        message = MIMEText(entry.summary, 'html')
        message['From'] = "ArchNews"
        message['Subject'] = entry.title
        message['Message-ID'] = entry.id
        mail.add(message)

mail.close()

The second is a script that should be added to your .zshrc or .bashrc depending on your shell. It will check the mbox file for new messages and print a notice to your terminal.

~/bin/unread.py || echo "$? breaking changes."
#!/usr/bin/env python
from mailbox import mbox, mboxMessage

mail = mbox('/var/spool/mail/news')
new = 0
for m in mail:
    if 'O' not in m.get_flags():
        new += 1

mail.close()
exit(new)

To get rid of the warning, open the mbox with a mail viewer. Probably mutt, knowing a few Arch users. I simply run mail to mark the messages as old, and optionally actually read them.

mail -f /var/spool/mail/news
p 1 # print first message
q   # write mbox and quit

i3 on Fedora Xfce

i3 on xfce

It’s distro hopping time again. This time I decided to Pick Fedora with Xfce as the desktop environment and i3 as the window manager.

I previously used Crunchbang and Arch before that. On Arch I built my own setup from scratch, but kept running into missing features and breakage. On Crunchbang I used the default setup, but being a Debian derivative, it has very old software.

What I hope to find in Fedora’s Xfce spin is a light distro that is up-to-date and provides a nice out-of-the-box experience. I only want to replace xfwm4 with i3.

Most of the stuff in this post is based on this guide adapted for Fedora and my personal preferences.

The first step is easy:

yum install i3

Next, you need to stop the Xfce window manager and start i3 instead.

In the Xfce menu, go to “Session and Startup” and then to “Application Autostart”. Add an entry for i3 there.

Stopping xfwm4 is done in the “Session” tab. Simply set its “Restart Style” to “Never”.

You might also want to stop xfdesktop and xfce4-panel. xfdesktop provides a window with icons, which is awkward when it gets tiled by i3. xfce4-panel provides the menu bar, which I kept around until I was sure I could do everything I needed using i3.

Then I made some modifications to the i3 config file.

# use the Xfce terminal instead of urxvt
bindsym $mod+Return exec xfce4-terminal
# mimic Crunchbang, I remapped tabbed layout to $mod+t
bindsym $mod+w exec firefox
# make sure xfce notifications display properly
for_window [class="Xfce4-notifyd"] floating enable;border none; focus mode_toggle
# uncomment the i3 dmenu wrapper
# this gives you easy access to Xfce settings
# and hides obscure utilities
bindsym $mod+d exec --no-startup-id i3-dmenu-desktop
# remap the exit command to properly exit Xfce
bindsym $mod+Shift+e exec xfce4-session-logout
# use conky for displaying some stats
bar {
    status_command conky
}

My .conkyrc is very simple

out_to_console yes
out_to_x no
TEXT
RAM ${membar} | \
CPU ${cpubar} | \
BAT ${battery_bar BAT1} | \
$acpitemp C | \
${time %a %d %b %R}

The only thing that remains is installing patented software for proper font rendering and playing multimedia. Fedora is made by RedHat which is based in the US. It turns out you can’t have subpixel smoothing or play MP3 files because of that.

If you’re wondering why this is not a problem for Arch or Ubuntu, it is because Canonical is based on the Isle of Man and Arch isn’t based anywhere at all.

The solution to all of this is to take a look at RPM Fusion. A third-party repo which has all the stuff you need.

Alternatively there is also a repo for the Freetype infinality patches, but so far I have not managed to make my fonts look the way I like.

Concatenative programming in Clojure

Just before I went to EuroClojure I read about Gershwin, a concatenative programming language based on Clojure.

With a lot of time to think and code on the train between Amsterdam and Berlin and back, I thought: Why make this a language at all?

Using the threading macro you can make a basic stack program as follows.

(def add [stack]
  (conj (drop 2 stack)
        (apply + (take 2))))

(-> () ; the stack
  (conj 1)
  (conj 2)
  add)
;; => (3)

After that, things got interesting. What if I used a queue instead of a stack? What if I used any number of queues and stacks?

I switched to using thrush, wrote a function to generate words from Clojure functions, and did some magic to apply words to multiple stacks.

(defn nth-stack [n f]
  #(apply update-in % [n] f %&))

(thrush [() ()]  ; data stack and return stack
  (lit 2) dup c+ ; add numbers
  (lit 4) c=     ; verify result
  >r)            ; put bool on return stack
;; => [() (true)]

What if I used clojure.core.reducers/fold instead of reduce in thrush? Could I use dataflow programming and continuations to parallelize programs?

mind blown

I failed at parallelization, but I surely achieved dataflow programming.

The idea is that you have a contiunation-passing-style function for popping of the stack. That function either calls the continuation with the head and tail of the stack, or returns a negative stack which will call the continuation when an item is conj‘d.

(deftype NegStack [popfn stack]
  clojure.lang.ISeq
  ...
  (cons [_ o] (popfn o stack))
  ...)

(defn mpeek [stack cont]
  (if (seq stack)
    (cont (first stack) (next stack))
    (NegStack. cont stack)))

(defn add [stack]
  (mpeek stack (fn [car cdr]
    (mpeek cdr (fn [cdar cddr]
      (conj cddr (+ car cdar)))))))

(thrush () (lit 2) add (lit 2))
;; => (4)

Yes, you can have prefix, infix, postfix and otherfix all you want. But not on a fork-join pool.

I had it all figured out, including concatenating negative stacks. It’s just not conceptually sound. Imagine this program

(thrush () (lit 2) (lit 2) mul (lit 5) (lit 6) add add)
;; => (15)

Using my fork-join-based pthrush thish might be split up as

(mconcat
  (thrush () (lit 2) (lit 2))
  (thrush () mul (lit 5) (lit 6) add add))

The first block produces (2 2), the execution of the second block is more tricky.

  1. mul produces a negative stack
  2. 5 and 6 are conj‘d onto this stack, resulting in (30)
  3. The add’s consume 30 and produce a negative stack
  4. This negative stack is concatenated to (2 2), resulting in (34)

The problem is that mul got applied to (5 6) instead of (2 2) because of how the program was split.

It might still be possible to paralellize by analyzing the stack effect of words, but dataflow is definitely not the way to go.

All my experiments so far can be found on Github at pepijndevos/staack

Published on