xmonad

Table of Contents

css change

Chrome のローカルオーバーライド機能を使ってWebサイトのファイルをローカルのファイルに置き換える

CSS の基本 by MDN

で、CSSファイルを見ると複数の色が定義されてる。どれが *.htmlのどれに対 応してる? htmlファイルを開くと、細密充填の機械が読むだけー式。さあ どうする? そんな時は、ブラウザーのインスペクターだな。

リンク色は、#9E358F となってた。Chromeが親切だった。

a { text-decoration: none; }
a[href]:link { color: #9E358F; }
a[href]:visited {color: #6F5F9C; }
a[href]:hover { text-decoration:underline; }

各ブラウザごとのデフォルトのスタイルシート が、最強の奴だよって指定す るのかな。

p{color:red !important;}

こんなのを設定するのかな。

hlintと言う家庭教師

前回やったサーチ・アプリを診断してもらったら、次のアドバイスをされた。 家庭教師だな。

sakae@deb:/tmp/t/app$ hlint Main.hs
Main.hs:10:14-48: Suggestion: Move brackets to avoid $
Found:
  1 + (foldl max 0 $ map length seld)
Perhaps:
  1 + foldl max 0 (map length seld)

1 hint

ちょいと悔しいので、無駄を省く算段をしたい。文字列リストの長さリストを作成。 そいつに対して最大値というか最長の長さを求める。都合2回、リストをスキャ ンしてる。えいやで、関数合成。

let mlon = 1 + foldl (max . length) 0 seld

んが、

/tmp/t/app/Main.hs:9:31-36: error:
    • Couldn't match type ‘Int’ with ‘[Char]’
      Expected: [Char] -> [Char]
        Actual: [Char] -> Int
    • In the second argument of ‘(.)’, namely ‘length’
      In the first argument of ‘foldl’, namely ‘(max . length)’
      In the second argument of ‘(+)’, namely
        ‘foldl (max . length) 0 seld’
  |
9 |   let mlon = 1 + foldl (max . length) 0 seld  -- longst word length + 1
  |                               ^^^^^^

更に、mlonを参照してる後続行でもエラーとなってて、盛大な事この上ない。 やる気を削ぐ仕組みになってるんだな。

λ>  :t (max . length)
(max . length) :: Foldable t => t a -> Int -> Int

冷静に、合成した関数の型を確認。2引数を要求してるよ。と言う事は、合成 できないって事。やるなら、自前で関数を作れ。

let mlon = 1 + foldl (\b a -> max b $ length a) 0 seld  -- longst word length + 1

関数を書く時は、foldlの型を出しておいて、単に型引数を割り当てていくの が楽だ。きっと幼稚園児でも出来るだろう。

let mlon = 1 + foldl (\b -> max b . length) 0 seld  -- longst word length + 1

これは、格好つけたがりの中坊みたいだな。やり過ぎ注意。

Bug発見

上記の変更をテストしておきましょ。変更したら直にテストって誰かが吠えて いたな。鉄は熱いうちに打てってのは、とっても大事な事。

λ>  :main ""
"-----1----12"
"---123--1234"
"-12345-----a"
"----aa---aaa"
"--aaaa-----b"
"----bb---bbb"
"--bbba---abc"

ちょいと指が早合点して、文字列の入力をすっとばしてしまった。これでも答 が出てくるのね。まあ、実際のアプリでコマンドラインからNULL文字列を渡す のは難しいだろうから、隠しコマンドだな。

ひるがえって、想定外の事が起ったらどうなるか、アインシュタイン宜しく、 思考実験する。

たとえば、文字列の流さは、端末の桁数より短かいって、無意識に仮定してた。 この仮定が破られる事があったら、どうなる?

splitAt 0 xs を根底で使用してる、インチキsplitは停止しなくなるだろう。 その結果は、暴走という事になるはず。

実際に実験すると、永遠に、"" が表示された。そりゃそうだ、再帰が終了し ないからね。じゃ、これをどう防ぐ?

split :: Int -> Int -> [[Char]] -> [[Char]]
split z 0 _  = []
 :

システムコール宜しく、イリーガルな入力に対しては、即実行終了にしてしま うのがよさそう。更に予防的な観点から、zも同様な対策を施すのがよさそ うだ。まあ、これらが負数の場合はとかがあるけどね。

ls

本物のlsでは、端末の桁数より、長いファイル名が有った時、それをどう、扱っ ている? プチ調べてみる。勿論、調べ物はOpenBSDね。久しぶりの登 場だ。まずは、挙動確認って事で、端末の桁数を30桁に制限。

vbox$ ./a.out
Makefile  ls.c      utf8.c
a.out     ls.h      util.c
cmp.c     main.c
extern.h  print.c

それから、長いファイル名のものを混ぜ込み。

vbox$ ./a.out
Makefile
a.out
abcdefghijklmnopqrstuvwxyz0123456789
cmp.c
 :

1ファイル/1行モードに移行した。

ソースの中心は、ls.c

/* Terminal defaults to -Cq, non-terminal defaults to -1. */
if (isatty(STDOUT_FILENO)) {
        f_column = f_nonprint = 1;
} else {
        f_singlecol = 1;
}

termwidth = 0;
if ((p = getenv("COLUMNS")) != NULL)
        termwidth = strtonum(p, 1, INT_MAX, NULL);
if (termwidth == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
    win.ws_col > 0)
        termwidth = win.ws_col;
if (termwidth == 0)
        termwidth = 80;

端末かどうかの判定とか、桁数の導出をしてる。そして、えいやでgdb君。

#0  printcol (dp=0xcf7f7734) at print.c:172
#1  0x16fed6d8 in display (p=0x722d0580, list=0x722d0a80) at ls.c:576
#2  0x16fecb1f in traverse (argc=1, argv=0x36fea20c <ls_main.dotav>,
    options=25) at ls.c:397
#3  0x16fec870 in ls_main (argc=0, argv=0xcf7f78b8) at ls.c:335
#4  0x16fed7a6 in main (argc=1, argv=0xcf7f78b4) at main.c:12

コードを追跡してみると、 fts_read で、ファイルの情報を収集。lsの各種 表示に必要な情報にdisplay()を使ってまとめあげる(ex. dp->maxlenは最大ファ イル名長)。

compute_columns() 内で、どう表示するか決定。

colwidth = dp->maxlen;
colwidth += 1;
mywidth = termwidth + 1;        /* no extra space for last column */

if (mywidth < 2 * colwidth) {
        printscol(dp);
        return (0);
}
*pnum = mywidth / colwidth;
return (mywidth / *pnum);               /* spread out if possible */

printscol()が使われるのは、長いファイル名が検出された場合だ。短いファ イルの時は、printcol()だ。まぎらわしい名前付けって思うのは、漢な人だか らかな。たったの1文字違いですからね。printsolocolとか、ソロを強調して ほしかったぞ。s はソロと解釈したけど、シングルとも言えるな。

ボーと生きていると、増殖する「ChatGPTもどき」にご用心 チェック・ポイ ントが注意喚起 こういうのに引っかかるぞ。今や人を集める、水飲み場ですから。 boss@company.comとboss@cornpany.comの違いをサッと見分けられるか?

void	 printcol(DISPLAY *);
void	 printacol(DISPLAY *);
void	 printlong(DISPLAY *);
void	 printscol(DISPLAY *);
void	 printstream(DISPLAY *);

まぎらわしい名前の一覧(って、恨みでもあるんか)。せめて print_xxx と かできなかったんでしょうかね? これらの関数は、高階関数として利用され てるよ。どれを選ぶかは、膨大なオプションの組み合わせによる。

ls opt paths = traverse printfcn paths
      where
        printfcn = case opt of
	  (-l) = printlong
	  (-x) = printacol
	   :
	   _   = printcol

超いいかげんな、lsコマンドのhaskell風構造表記。lsコマンドの解説で、 本を書いてしまった人がいるからなあ。こんな絵を出すとブッ飛ばされます。

guard 戦法

上で出てきた、splitをより安全にする為に、ガード戦法を取り入れてみる。 パターンマッチ方式じゃ、ピンポイントのチェックしか出来ないからね。

ちゃんとしておけば、hoogleにも登録できる、逸品になるぞ。 まあ、system callみたいに、引数は全部チェックするという厳格さの適用だ けどね。

split :: Int -> Int -> [[Char]] -> [[Char]]
split z n xs
  | z <= 0    = error "Must be positive"
  | n <= 0    = error "Uum ... negative"
  | xs == []  = []
  | otherwise = aa : split z n ts
      where (hs, ts) = splitAt n xs
            aa = foldr (\s t -> pad z s ++ t) "" hs

最初エラーメッセージを同一にしてたんだけど、それじゃMSみたいだから、変 更してみた。ウーム、マンダムって昭和のおじさんしか知らないCMから、頂い てしまった。

xmonad

タイル型ウィンドウマネージャを使ってみよう

タイル型ウィンドウマネージャという新たな世界観に衝撃を受けた!XmonadをつかってワクワクCUI生活

ArchLinuxにXorgを最小限インストールしておしゃれにxmonadする

The following NEW packages will be installed:
  ghc libbsd-dev libffi-dev libghc-data-default-class-dev
  libghc-data-default-class-doc libghc-data-default-dev
  libghc-data-default-doc libghc-data-default-instances-containers-dev
  libghc-data-default-instances-dlist-dev
  libghc-data-default-instances-old-locale-dev libghc-dlist-dev
  libghc-extensible-exceptions-dev libghc-old-locale-dev libghc-old-time-dev
  libghc-random-dev libghc-random-doc libghc-semigroups-dev
  libghc-setlocale-dev libghc-utf8-string-dev libghc-utf8-string-doc
  libghc-x11-dev libghc-x11-doc libghc-x11-xft-dev libghc-x11-xft-doc
  libghc-xmonad-contrib-dev libghc-xmonad-contrib-doc libghc-xmonad-dev
  libghc-xmonad-doc libmd-dev xmonad
0 upgraded, 30 newly installed, 0 to remove and 0 not upgraded.
Need to get 82.8 MB of archives.
After this operation, 773 MB of additional disk space will be used.

ghcが新規に入るのか。混ぜるな危険を承知の上で導入する。既存のものと 交雑して、おかしな事にならない様に祈りを捧げておこう。

sakae@deb:~$ /usr/bin/ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.8.4
sakae@deb:~$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 9.2.7

とりあえず、下記の設定でstartxする。単にicewmを止めてxmonadにしただけ。

sakae@deb:~$ cat .xinitrc
xrdb ~/.Xresources
setxkbmap -option ctrl:swapcaps
xterm -r -g 80x39 &

xmonad
#icewm
#ctwm

icewmに比べて起動が速い。起動すると、赤枠の全面xtermが表れた。 xtermの追加は、Alt + Shift + Enter, フォーカスのあるアプリを終了させるには Alt + Shift + c、Alt + Shift + qで、xmonadを終了できる。今日は3個のキー バインドを覚えましたからね。

おっと、それだけじゃ実用にならないので、 Alt + p で、ランチャーがでてくる。Alt + number(1-9) で、仮想画面の指定 も覚えておこう。

これ以上の操作は、 ウィンドウ操作の基本 を参照だな。

sakae@deb:/usr/share/doc$ ls -d libghc*
libghc-data-default-class-dev/                 libghc-semigroups-dev/
libghc-data-default-class-doc/                 libghc-setlocale-dev/
libghc-data-default-dev/                       libghc-utf8-string-dev/
libghc-data-default-doc/                       libghc-utf8-string-doc/
libghc-data-default-instances-containers-dev/  libghc-x11-dev/
libghc-data-default-instances-dlist-dev/       libghc-x11-doc/
libghc-data-default-instances-old-locale-dev/  libghc-x11-xft-dev/
libghc-dlist-dev/                              libghc-x11-xft-doc/
libghc-extensible-exceptions-dev/              libghc-xmonad-contrib-dev/
libghc-old-locale-dev/                         libghc-xmonad-contrib-doc/
libghc-old-time-dev/                           libghc-xmonad-dev/
libghc-random-dev/                             libghc-xmonad-doc/
libghc-random-doc/

ここに、肌色でリンクを表示するhtml類が集合してる、よく見ておけ。

A dynamically tiling X11 window manager that is written and configured in Haskell.

がxmondの正体なんだけど、怖くて近付けない 人は、luaで作成されたのも有るよ。

What is this awesome window manager?

カスタマイズ

修飾キーが Altって emacsと競合するなあ。これは是非、Windowsキーに変更 したいぞ。xtermのバックグラウンド色を黒にしておきたい。どうする?

Xmonad/Config archive

設定ファイルは、~/.xmonad/xmonad.hs とな。

Xmonad for FreeBSD 同窓会の雰囲気。キーの説明があって助かった。

import XMonad

main = xmonad defaultConfig
        { modMask = mod4Mask -- Use Super(Win key) instead of Alt
        , terminal = "xterm -r"
        }

古いghcを使うように、一時的にPATHの先頭に/usr/binを指定。そうしておい て、Alt-q で、更新。これでいいはずなんだけど、エラーだよ。最初は、 import Xmondが見付からないなんて、とぼけた事をほざいていたけど、数度実行した。 そうしたら、 エラーログが、こんなになって、どうやら成功した。

sakae@deb:~/.xmonad$ cat xmonad.errors

xmonad.hs:3:15: warning: [-Wdeprecations]
    In the use of ‘defaultConfig’
    (imported from XMonad, but defined in XMonad.Config):
    Deprecated: "Use def (from Data.Default, and re-exported by XMonad and XMonad.Config) instead."
  |
3 | main = xmonad defaultConfig
  |               ^^^^^^^^^^^^^

xmonad –recompile でもいいのか。文句を言われつつも、狙った機能が実現 できたから、良しとしよう。残骸は下記の様であった。

sakae@deb:~/.xmonad$ ls -l
total 3300
-rw-r--r-- 1 sakae sakae     307 May 20 07:36 xmonad.errors
-rw-r--r-- 1 sakae sakae    2922 May 20 07:36 xmonad.hi
-rw-r--r-- 1 sakae sakae     142 May 20 07:27 xmonad.hs
-rwxr-xr-x 1 sakae sakae 3355344 May 20 07:36 xmonad-i386-linux*
-rw-r--r-- 1 sakae sakae    5524 May 20 07:36 xmonad.o

まて、残骸なんて失礼な事を言うな。mainが有るなら、それはアプリだ。新ら しい設定が反映された奴だ。きっと、アーなってるに違いない。

質問があります

まずは、軽く確認。

sakae@deb:~/.xmonad$ ls -l xmonad-i386-linux /usr/bin/xmonad
-rwxr-xr-x 1 root  root  2244896 Aug 15  2020 /usr/bin/xmonad*
-rwxr-xr-x 1 sakae sakae 3355344 May 20 07:36 xmonad-i386-linux*

startxする前後で、プロセスがどうなってるか確認。冒頭の+記号は、スター ト後に生えたもの。

-  989 pts/2    R+     0:00 ps awx
+  990 tty1     S+     0:00 /bin/sh /usr/bin/startx
+ 1012 tty1     S+     0:00 xinit /home/sakae/.xinitrc -- /etc/X11/xin
+ 1013 tty1     Sl     0:00 /usr/lib/xorg/Xorg -nolisten tcp :0 vt1 -k
+ 1027 tty1     S      0:00 sh /home/sakae/.xinitrc
+ 1035 tty1     S      0:00 xterm -r -g 80x39
+ 1036 tty1     S      0:00 /home/sakae/.xmonad/xmonad-i386-linux
+ 1038 pts/3    Ss+    0:00 bash
+ 1043 pts/2    R+     0:00 ps awx

手に取るようにXの起動の仕組みが見えますなあ。オイラーが startxで起動。 .xinitrcが読みこまれてXorgが動きだす。.xinitrcをシェルスクリプトとして実 行。xtermが起動してから、ウィンドウ・マネージャである xmonad-i386-linx が起動。xtermの中でbashが動きだして完了。

注意としては、.xinitrc中には、xmonadとしか記述してない点。こいつは、 /usr/bin/xmonadのはず。ゆえに、一度こいつが起動して、この中で、新しい 設定のxmonad-i386-linuxを見付けて、そいつに移譲してるんだな。

なんで、こんな面倒な仕組みになってる? 変更点だけを記述した設定ファイ ルを用意して、それを取り込んでもよかったはず。

それは美意識の問題だろう。オイラーがサンプルで作成したアプリはシングル バイナリーにした。理由は、余計なものはいらないって事だった。ただのテキ ストファイルだと、間違って変更しちゃう可能性がある。それに文法まちがい も予想される。一度コンパイルしたものだと、これらを払拭できる。多分そん な事では、なかろうか。

興味深いメッセージが出てきたなあ。

sakae@deb:~$ xmonad -version
XMonad is recompiling and replacing itself another XMonad process because the current process is called "xmonad" but the compiled configuration should be called "xmonad-i386-linux"
XMonad will use ghc to recompile, because "/home/sakae/.xmonad/build" does not exist.
XMonad skipping recompile because it is not forced (e.g. via --recompile), and n
either xmonad.hs nor any *.hs / *.lhs / *.hsc files in lib/ have been changed.
xmonad-i386-linux: user error (unrecognized flags:["-version"])

pre check

太い括弧(ex. <a href="..">hoge</a>みたいな奴)に飽きてきたので、正統な 括弧で行きます。んで、下調べ。

sakae@deb:~$ t scheme
                 husk-scheme            husk-scheme-libs
     micro-recursion-schemes   monadic-recursion-schemes
 purescheme-wai-routing-core           recursion-schemes
       recursion-schemes-ext        recursion-schemes-ix
                sugar-scheme
sakae@deb:~$ t lisp
    atto-lisp clisparkline    haskelisp       helisp    hsc3-lisp   lispparser
     megalisp

48Hr

haskellの本家に資料があがっていた。オイラーだと、とても48時間ではおさ まらなくて、いろいろな疑問をクリアーしながら進むであろうから、72時間は かかるだろう。

NHKの名物番組にあったよな。72時間なんとかって奴で、色々な人生を見せて くれる奴が。ああ、街録なんて番組もあったな。

Write Yourself a Scheme in 48 Hours

Write You A Scheme, Version 2

micro scheme

こちらは、日本人による日本人の為の貴重な資源です。つつしんで拝読いたし ます。

micro Scheme 編

golang project

GoでWebAssembly――Go標準のWebAssemblyサポートを体験する

アンテナは高い程よい は、常識です。ワッチしておかないとね。 特に、プロジェクトの作成方法で、右往左往するのよ。

rust,haskell,golangぐらいを抑えておけば十分だろうけど。

いつか、比較表を作りたいな。いや、きっと既に誰かが、やっているだろう。

おっと、Juliaを忘れちゃいけないよーー(と、リンダ風、謎)。奥深い所にscheleが潜んでいるか らね。最近、 実践Julia入門 なんて本が出たみたい。


This year's Index

Home