inside xmonad

Table of Contents

awesome

debianなマシンにxmonadを入れたので、FreeBSDには、もうひとつのタイル型 ウィンドウマネージャを入れてみる。参考にしたのは下記。

タイル型ウィンドウマネージャ awesome のすすめ (後編)

何の苦もなく動いた。なんかこれ、以前にやった記憶があるぞ。全面が一望で きて、株のトレーダーになった気分だな。いちいちウィンドウの重なりを切り 替える必要もないので、監視画面には丁度いいぞ。

それぞれの端末と言うかウィンドウのタイトルバー右側に、各種アイコンが並 んでいて、とっても目障り。その設定は、こうなっている。いらない所をコメ ントにすればよい。ってか、そもそもタイトルバーなんて不要と思うけど、ど うよ。

-- Add a titlebar if titlebars_enabled is set to true in the rules.
client.connect_signal("request::titlebars", function(c)
   :
        { -- Right
            awful.titlebar.widget.floatingbutton (c),
            awful.titlebar.widget.maximizedbutton(c),
            awful.titlebar.widget.stickybutton   (c),
            awful.titlebar.widget.ontopbutton    (c),
            awful.titlebar.widget.closebutton    (c),
            layout = wibox.layout.fixed.horizontal()
        },

juliaup

前回みつけた本の見本を見てたら、でてたので 、、、

JuliaLang / juliaup

curl -fsSL https://install.julialang.org | sh
Juliaup will be installed into the Juliaup home directory, located at:

  /home/sakae/.juliaup

The julia, juliaup and other commands will be added to
Juliaup's bin directory, located at:

  /home/sakae/.juliaup/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /home/sakae/.bashrc
  /home/sakae/.profile

Julia will look for a new version of Juliaup itself every 1440 minutes when you start julia.

You can uninstall at any time with juliaup self uninstall and these
changes will be reverted.

✔ Do you want to install with these default configuration choices? · Proceed with installation

1440 minutesって、どれぐらいの時間? 思わず計算しちゃったぞ。毎日じゃ ん!!

今回のupで、Version 1.9.0 (2023-05-07)が来た。1年前は、julia-1.7.3だっ たから、順調に進んでいるな。

今回利用したインストーラーは、rustのそれを変更したものなのね。ghcupもそう だったのかしらん?(スクラッチから作成されてました) まあ、この手のやつは、やる事が同じだから、多いに有 効利用するのがいいでしょう。

# This script is adapted for juliaup from the original rustup repository
# over at https://github.com/rust-lang/rustup. Names and urls have been
# changed during the adaptation.

pipe

楽しいH本を、とりあえず読了。モノイドなんてのが出てくるけど、これって 数学で言う群ではなかろうか。以前そんな事を解説したページがあったな。 これか、 半群,モノイド,可換群

そんな事より、オイラーが感銘を受けたのは、これ。二項演算子の定義。 こういう詐欺みたいな定義がhaskellで出来ちゃう所が凄い。

ghci> x -: f = f x
ghci> 3 -: (+1)
4
ghci> 3 -: (*2) -: (+1)
7

rubyとかで言う、メソッド・チェーンだ。見方を変えれば、パイプだ。凄いこっ ちゃ。

ghci> :t (-:)
(-:) :: t1 -> (t1 -> t2) -> t2

大事な事なんで、型を確認。以前は、型々言うなって言ってたけど、最近は、 型様ですよ。

パイプと感じてしまったけど、別の見方をすれば、関数合成、それも、左側 から実行されてく、素直なやつだ。

前 中 後置法

上の例で、ことわりもなく、(+1) (*2) なんてのが出てきた。これは、演算子 を、どこに配置するかで、3つの方法がある。

(+ 1 2)  前置法  schemeとかね。英語圏の人なら、add 1 with 2
1 + 2    中置法  人間様用ってか、算数の世界の標準表記法
1 2 +    後置法  HPの電卓とか、 漢な人なら、1と2を足すと素直に表現できる

普通は、人間様用でいいんだけど、演算子を前におきたい場合もある。そんな 時は、括弧でくくってやればよい。

ghci> (+) 2 3
5
(+ 2) 3
5
ghci> (+2) 3
5

かっこを途中に置いてもよい。更に、括弧のなかのスペースを省いてもよい。 なぜかと言うと、演算子は記号で構成されてるから、データの分離は造作もな いからだ。そこはかとなく、schemeの香りがして、オイラーは好きだな。 この方法を使うと、いとも簡単に、特定の数値を加算する関数が作成できる。

ghci> div 10 5
2
ghci> 10 `div` 5
2

じゃ、記号以外の関数はどうか? 整数の割り算には、divが用意されてる。人 間様用にするには、関数名を、バッククォートで囲む必要がある。

モナド

これも数学の世界の話だそうだ。なんでも、圏という世界らしい。そんな物に 首をつっこんじゃうと日が暮れるので、ぐっとカジュアルに行く。 なんで突然モナドかと言うと、上でとりあげた、パイプの演算子っぽいのが、 H本に出てたから。そして、こちらにも モナドがいっぱい!!

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing  >>= _  =  Nothing    -- 失敗した計算は Nothing を返す
(Just x) >>= f  =  f x        -- 値 x に関数 f を適用する

記号だけで構成された関数 >>= を定義してる。上でやったパイプのパターン ト一緒である。これがオイラーのアハ体験である。アハと言えば脳科学者の、 あの人だな。

haskellのひとつの壁として恐れられているのはmonad。そしてschemeで恐れら れているのは、call-with-current-continuation。

このcall/ccも、モナドの親戚になるんか。そんな事、初めて知ったぞ。 深い所でつながっているのね。

入れ替え

上で数学の群なんてのを、思いだされてしまった。 足し算やかけ算では、項を入れ替えても大丈夫。いわゆる、交換則ね。 式でかくと

a + b  =  b + a
a * b  =  b * a

子供の宿題で、1本120円の鉛筆を3本買いました。計算式を作って説明しなさ いってのが、あるらしい。どっちを先に持ってくるかで、バツになるらしい。 なんか、不毛な問いにおもえるぞ。

ああ、行列のかけ算は、交換できなかったんだな。大事な事なんで、その手の 本では、くどい程説明してたな。 この交換則が成り立たない演算には、引き算もある。で、困ったhaskellの人は、 素晴しい関数を発明した。

ghci> (-) 3 5
-2
ghci> flip (-) 3 5
2
ghci> :t flip
flip :: (a -> b -> c) -> b -> a -> c

あら、赤字だわよ。魔法の関数で、黒字にしてもらいましょ。と、粉飾決算が できるようにした。これを知った時は、仰天したぞ。

xmonad again

前回xmonadを起動させた時、途中からxmonad-i386-linuxにすり代わっていた。 ちょいとでも、unixをかじった人なら、それはね、forkされたものがexecveと かで、動いているのよと、想像がつく。セオリー通りになってるかソースを取 り寄せて確かめてみたい。

first see xmonad.cabal

build-depends:   base                  >= 4.11 && < 5
               , X11                   >= 1.10 && < 1.11
               , containers
               , data-default-class
               , directory
               , filepath
               , mtl
               , process
               , setlocale
               , time
               , transformers          >= 0.3
               , unix

パッケージを作成するって事は、これらを全部コンパイルすると言うとても大 変な作業ですよ。このうち、どれだけが標準になってるのだろう? 次はエン トリーポイントの確認。それはトップにある Main.hsを確認する事だな。

import XMonad

main :: IO ()
main = xmonad def

defて、意味深な引数名だな。そして、核心に迫っていく。得意の流し読み戦 法でいく。

xmonad-0.17.2/src/XMonad/Main.hs

buildLaunch :: Directories -> IO ()
buildLaunch dirs = do
    whoami <- getProgName
    let bin = binFileName dirs
    let compiledConfig = takeFileName bin
    unless (whoami == compiledConfig) $ do
      trace $ concat
        [ "XMonad is recompiling and replacing itself with another XMonad proce\
ss because the current process is called "
        , show whoami
        , " but the compiled configuration should be called "
        , show compiledConfig
        ]
      recompile dirs False
      args <- getArgs
      executeFile bin False args Nothing

このconcatされたメッセージは、以前おめにかかったな。まあ、それはいいと して、executeFileってのが怪しそうなので、hoogleしてみる。

executeFile

executeFile :: FilePath -> Bool -> [String] -> Maybe [(String, String)] ->
IO a
unix System.Posix.Process
executeFile cmd args env calls one of the execv* family, depending on
whether or not the current PATH is to be searched for the command, and
whether or not an environment is provided to supersede the process's current
environment. The basename (leading directory names suppressed) of the
command is passed to execv* as arg[0]; the argument list passed to
executeFile therefore begins with arg[1].

ビンゴでいいのかな。

can not use ghci's ctags/etags

:etags [<file>]             create tags file <file> for Emacs (default: "TAGS")
:ctags[!] [<file>]          create tags file <file> for Vi (default: "tags")
                            (!: use regex instead of line number)

ghciにこんなコマンドが用意されている。が、これが使えるのは、コンパイル が成功してパッケージがロードできた場合だ。今回のように、ソースを観光気 分で見たい場合は無理だ。

しょうがなく、こんな方法で、お茶を濁す。拡張ctagsコマンドだとetags形式 が作成できたり、haskellのファイルも扱える。

[sakae@arch xmonad-0.17.2]$ ctags -e `find . -name '*.hs'`

Main.hsでxmonadを探すと、モジュール名が、わんさかと候補にで てくる。そのうちの xmonad conf = do てのが、目指すやつだ。旅の始まり。

/tmp/xmonad-0.17.2/src/XMonad/ManageHook.hs
16: module XMonad.ManageHook where
/tmp/xmonad-0.17.2/src/XMonad/Main.hs
18: module XMonad.Main (xmonad, launch) where
=>: xmonad conf = do
/tmp/xmonad-0.17.2/src/XMonad/Layout.hs
19: module XMonad.Layout (

これが、その定義

xmonad :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()
xmonad conf = do
    installSignalHandlers -- important to ignore SIGCHLD to avoid zombies

    dirs <- getDirectories
    let launch' args = do
              catchIO (buildLaunch dirs)
              conf'@XConfig { layoutHook = Layout l }
                  <- handleExtraArgs conf args conf{ layoutHook = Layout (layoutHook conf) }
              withArgs [] $ launch (conf' { layoutHook = l }) dirs

getDirectoriesにカーソルを合わ せて、追跡。

-- | Check whether the config file or a build script is in the
-- @~\/.xmonad@ directory
xmDirs :: IO Directories
xmDirs = do
    xmDir <- getAppUserDataDirectory "xmonad"
    conf  <- doesFileExist $ xmDir </> "xmonad.hs"
    build <- doesFileExist $ xmDir </> "build"

    -- Place *everything* in ~/.xmonad if yes
    guard $ conf || build
    pure Directories{ dataDir = xmDir, cfgDir = xmDir, cacheDir = xmDir }

なんとなく、ユーザーは、xmonadというdirを所持してて、その中にxmonad.hs かbuildが有るか確認してるっぽい。getAppUserDataDirectoryに照準を合わせ てJumpしようにも、そんなの無いという。ならば、外部のやつだな。hoogleに 問い合わせ。

この、そんなの無い問題は、C言語のソースを閲覧してる時にも、煩雑に経験 してた。そんな時はmanするんだぞってのが体に染み込んでいますからね。

getAppUserDataDirectory

getAppUserDataDirectory :: FilePath -> IO FilePath
directory System.Directory, hledger Hledger.Cli.Script
Obtain the path to a special directory for storing user-specific application
data (traditional Unix location). Newer applications may prefer the the
XDG-conformant location provided by getXdgDirectory (migration guide). The
argument is usually the name of the application. Since it will be integrated
into the path, it must consist of valid path characters.

  • On Unix-like systems, the path is ~/.<app>.
  • On Windows, the path is %APPDATA%/<app> (e.g. C:/Users/<user>/AppData/
    Roaming/<app>)

こんな調子でいけばいいんだな。 オイラーの予想では、起動したユーザーを、getuid相当で調べ、やおら、その ユーザーのHOME-Dirを検索してると思った。こんな便利か関数が提供されてる とは。。 だから、人様のソースは覗いてみるものだ。

guardも良い機会だから調べておく。

A definition of safeDiv using guards, but not guard:

safeDiv :: Int -> Int -> Maybe Int
safeDiv x y
    | y /= 0    = Just (x `div` y)
    | otherwise = Nothing

A definition of safeDiv using guard and Monad do-notation:

safeDiv :: Int -> Int -> Maybe Int
safeDiv x y = do
    guard (y /= 0)
    return (x `div` y)

pureも調べたいぞ。確かH本にも出てきていたけど、そんなものあるんだとス ルーしてた。実業の世界に身を置いて、ああ、ちゃんと勉強しとくんだったと、 反省する、今日この頃。まあ、そんなものよ。今度はH本のピンポイント勉強 だな。

ghci> :t pure
pure :: Applicative f => a -> f a

これで調べた積りにしておこう。モナドの片割れだな。

watch INSTALL.md

現在GHCをちゃんと使おうとしたら、パッケージのハンドリングを行なってく れる、stackかcabalを使わざるを得ない。両派に対応した説明がきちんと、な されていた。オイラーは、接頭語のstackを強要されるのが嫌なんで、cabal派 閥。

ghcupを使えの他にも、こんな説明がでてた。Linux重視。

$ sudo apt install cabal-install    # Debian, Ubuntu
$ sudo dnf install cabal-install    # Fedora
$ sudo pacman -S cabal-install      # Arch
$ cabal update
$ cabal install --package-env=$HOME/.config/xmonad --lib xmonad xmonad-contrib
$ cabal install --package-env=$HOME/.config/xmonad xmonad

裸のghcを使う場合は、

#!/bin/sh

exec stack ghc --  \
  --make xmonad.hs \
  -i               \
  -ilib            \
  -fforce-recomp   \
  -main-is main    \
  -v0              \
  -o "$1"

もちろん、xmonad.hsは必要で、こんなのを用意するみたい。これがデフォの 設定なんだな。ああ、ちゃんと用意されてた。

import XMonad

main :: IO ()
main = xmonad def

ソースを閲覧する時は、事前に付属文書も見て桶って事だな。

本当に見ていかなければいけない所は、Main.hs/launch なんだな。

-- main loop, for all you HOF/recursion fans out there.
-- forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e)
-- sadly, 9.2.{1,2,3} join points mishandle the above and trash the heap (see #389)
mainLoop dpy e rrData

最後はmainLoopでイベント待ちに入るんだけど、これどこからのもの? Xから かなあ。

import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)

このあたり? どうも違うな。Uum …..

mainLoop d e r = io (nextEvent d e >> rrUpdate e r >> getEvent e) >>= prehandle >> mainLoop d e r

これだな。ctagsを全面信用するな、の例でした。最後はgrepよ。ああ、普通 に再帰でループだな。

プチ悔しいので、

nextEvent :: Display -> XEventPtr -> IO ()
X11 Graphics.X11.Xlib.Event, xmonad XMonad
interface to the X11 library function XNextEvent().
nextEvent :: Display -> XEventPtr -> IO ()
xmonad-contrib XMonad.Config.Prime

しっかり補足されてた。hoogleは、信用していいよ。

repl love

repl love

Introduction; The Bolts and Nuts of Scheme Interpreters in Haskell

良い導入部だな。H本でつまみ復習するに最適。

Write You A Scheme, Version 2 勿論、この一節なのだけど。


This year's Index

Home