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
前回みつけた本の見本を見てたら、でてたので 、、、
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
Introduction; The Bolts and Nuts of Scheme Interpreters in Haskell
良い導入部だな。H本でつまみ復習するに最適。
Write You A Scheme, Version 2 勿論、この一節なのだけど。