du with ChatGPT

Table of Contents

図書館で

セルフ・レジならぬ、自分で貸出処理する装置が設置されてた。めざとく見付 けたオイラーが係りの人に申し出したら、ぞろぞろと3人ぐらいついてきた。 新し物好きな年寄が珍しかったのでしょうかね?

手取り足とり教えてくれたぞ。図書カードを刺しこんでください。次は、バー コードを光の部分にかざしてください。ピット音がしたら登録完了です。最後 は、終了ボタンを押してください。そうするとカードが戻ってきます。

ほら、マイクロソフトの駄目QRコード読取ソフトも見習えよ。市中の装置も、 ちゃんとフィードバックするようになってるぞ。

光の部分は、念をいれて、強く光っている部分があった。ここにバーコードを 持っていくのがこつとの事。さりげないガイド。年寄にもよく判る工夫がされ てた。素晴しい。

更に素晴しいのは、読書メーターが付いていた事。今迄に借りた冊数が表示さ れるサービス付き。12年通って2856冊だった。まだまだ借りるぞ。

nub

前回やったコードの一部。ここに出て来るnubって何?

-- Maps import name to haskell package name
iname2module :: Text -> IO (Maybe Text)
iname2module iname = do
  mod <- listToMaybe . Text.words <$> runp_ghc_pkgs ["--simple-output", "find-module", unpack iname]
  vprint $ "Import " <> unpack iname <> " resolved to " <> maybe "NULL" unpack mod
  return mod

inames2modules :: [Text] -> IO [FilePath]
inames2modules inames = map unpack . nub . sort . catMaybes <$> mapM iname2module (nub inames)

  ss_l1deps <- findModules ss_local >>= inames2modules >>= unpackModules >>= findSources

at base-4.16.4.0/Data/OldList.hs

-- | \(\mathcal{O}(n^2)\). The 'nub' function removes duplicate elements from a
-- list. In particular, it keeps only the first occurrence of each element. (Th\
e
-- name 'nub' means \`essence\'.) It is a special case of 'nubBy', which allows
-- the programmer to supply their own equality test.
--
-- >>> nub [1,2,3,4,3,2,1,2,4,3,5]
-- [1,2,3,4,5]
nub                     :: (Eq a) => [a] -> [a]
nub                     =  nubBy (==)

nubは骨子、essenceは核心って辞書に載ってたから、意味論では同義と思える けど、漢なオイラーには、ちと無理があるな。まあ坊主頭のオイラーには、エッ センシャル・リンスなんて不要ではあるんですが。。。unix的には、uniqなん だけどね。

import System.Process.Text (readProcessWithExitCode)

(ec, out, err) <- readProcessWithExitCode nm args inp

haskellから外部コマンドを呼ぶ例が出てたのでメモメモ。

du with ChatGPT

ChatGPTに、やらせてみる。だって、こういう事を考えておられる言語学者さ んが居るからね。 言語習得に見る知性の本質 そして、こんな記事も後押ししてくれてるからね。 「GitHub Copilot」でAIが提案したコード、業務でどれぐらい採用された?

linuxに有るduコマンドを使用して、
コマンドラインから入力したdir内に
有るファイル等の情報を出力して
ください。

言語は、haskellを使ってください。

こんな依頼をしてみたら、haskellだけの例を出してきた。ちゃんとduを使っ てくれと、強調したぞ。口答えをするんか、おまえは。

申し訳ありませんが、Haskellのプログラム内で直接Linuxの`du`コマンドを実行することはできません。
Haskell自体は素晴らしいプログラミング言語ですが、OSコマンドを直接実行するための機能は
標準ライブラリに含まれていないためです。

しかし、HaskellからOSコマンドを実行する方法として、`System.Process`モジュールを利用する方法があります。
これを使って`du`コマンドを呼び出すことができます。

以下のようなHaskellスクリプトを作成して`du`コマンドを実行します。

```haskell
-- モジュールのインポート
import System.Process

-- メイン関数
main :: IO ()
main = do
    putStrLn "ディレクトリのパスを入力してください:"
    dirPath <- getLine
    (_, Just hout, _, _) <- createProcess (proc "du" ["-b", dirPath]) { std_out = CreatePipe }
    result <- hGetContents hout
    putStrLn result
```

このコードでは、`System.Process`モジュールを使用して`du -b`コマンド(バイト単位でサイズを表示)を呼び出し、指定したディレクトリの情報を取得しています。

同様に、このHaskellコードをテキストエディタで作成し、適当なファイル名(例:`du_haskell.hs`)で保存します。そして、以下のコマンドでコンパイルと実行を行います。

```bash
# コンパイル
$ ghc --make du_haskell.hs

# 実行
$ ./du_haskell
```

プログラムはディレクトリのパスを入力するように要求し、`du`コマンドの出力(ファイルのサイズ情報)を表示します。

`du`コマンドの出力形式は、ディレクトリとそのサブディレクトリに含まれるファイルのサイズ
を表示します。ファイル名とそのサイズがタブ区切りで表示されます。`du`コマンドのオプショ
ンによって表示形式が変わるため、必要に応じてオプションを変更してください。

System.Process の根本的な奴を繰り出してきたな。期待してたもっと穏やか な物とは違うけど、つき合ってみるか。

コンパイル用のMakefileもどきをFreeBSD用に作成

[sakae@fb /tmp/hdu]$ cat Makefile
#! /bin/sh
ghc --make \
    -o a.out \
    -XOverloadedStrings \
    -package base \
    -package process \
    -threaded -rtsopts -with-rtsopts=-N \
    Main.hs
Main.hs:10:15: error:
    • Variable not in scope:
        hGetContents :: GHC.IO.Handle.Types.Handle -> IO String
    • Perhaps you meant ‘getContents’ (imported from Prelude)
   |
10 |     result <- hGetContents  hout
申し訳ありません、そのコードのエラーはhGetContents関数がスコープ内にないためです。
これはhGetContentsがSystem.IOモジュールにあるからです。

-- モジュールのインポート
import System.Process
import System.IO (hGetContents)

-- メイン関数
main :: IO ()
main = do
    putStrLn "ディレクトリのパスを入力してください:"
    dirPath <- getLine
    (_, Just hout, _, _) <- createProcess (proc "du" ["-b", dirPath]) { std_out = CreatePipe }
    result <- hGetContents hout
    putStrLn result

提示されたduのオプションを -sh に変更した。

[sakae@fb /tmp/hdu]$ ./a.out
ディレクトリのパスを入力してください:
/meet/WEB/*
du: /meet/WEB/*: No such file or directory
[sakae@fb /tmp/hdu]$ ./a.out
ディレクトリのパスを入力してください:
/meet/WEB
 28M    /meet/WEB
[sakae@fb /tmp/hdu]$ du -sh /meet/WEB/*
1.2M    /meet/WEB/hes2009
836K    /meet/WEB/hes2010
1.3M    /meet/WEB/hes2011
1.0M    /meet/WEB/hes2012
 :

何故、/meet/WEB/* で、そんなファイルとかディレクトリィーは無いとなるの? 普通にduを使うとOKなのに! これ、Linuxの試験問題の定番ぽいな。

check du by OpenBSD

答を確かめてみる。こういう時はソースが自由になるアレですよ。決して Linuxなんて使わないのさ。

vbox$ gdb -q a.out
Reading symbols from a.out...
(gdb) b prtout
Breakpoint 1 at 0x243d: file du.c, line 305.
(gdb) r /tmp/du
Starting program: /tmp/du/a.out /tmp/du

Breakpoint 1, prtout (size=120, path=0x62e76000 "/tmp/du", hflag=0) at du.c:305
305             if (!hflag)
(gdb) bt
#0  prtout (size=120, path=0x62e76000 "/tmp/du", hflag=0) at du.c:305
#1  0x177ad1b4 in main (argc=1, argv=0xcf7dca68) at du.c:179
(gdb) up
#1  0x177ad1b4 in main (argc=1, argv=0xcf7dca68) at du.c:179
179                                     prtout(howmany(p->fts_number,
(gdb) l
174                              * If listing each directory, or not listing files
175                              * or directories and this is post-order of the
176                              * root of a traversal, display the total.
177                              */
178                             if (p->fts_level <= maxdepth)
179                                     prtout(howmany(p->fts_number,
180                                         (unsigned long)blocksize), p->fts_path,
181                                         hflag);
182                             break;
183                     case FTS_DC:                    /* Ignore. */
(gdb) p *p
$1 = {fts_cycle = 0x0, fts_parent = 0x62e84e00, fts_link = 0x0,
  fts_number = 120, fts_pointer = 0x0, fts_accpath = 0x62e76000 "/tmp/du",
  fts_path = 0x62e76000 "/tmp/du", fts_errno = 0, fts_symfd = 0,
  fts_pathlen = 7, fts_namelen = 2, fts_ino = 38593, fts_dev = 65280,
  fts_nlink = 2, fts_level = 0, fts_info = 6, fts_flags = 0, fts_instr = 3,
  fts_spare = 0, fts_statp = 0x62e86758, fts_name = "d"}
(gdb) c
Continuing.
120     /tmp/du

今度は、引数を /tmp/du/* にしてみます。

(gdb) r /tmp/du/*
Starting program: /tmp/du/a.out /tmp/du/*

Breakpoint 1, prtout (size=2, path=0x4440b000 "/tmp/du/Makefile", hflag=0)
    at du.c:305
305             if (!hflag)
(gdb) bt
#0  prtout (size=2, path=0x4440b000 "/tmp/du/Makefile", hflag=0) at du.c:305
#1  0x145142ad in main (argc=6, argv=0xcf7dfc38) at du.c:200

注目すべき所は、argc=6 の部分です。最初の /tmp/du の場合は、argc=1 で した。* を指定すると、shellが、展開してくれるんですねぇ。ストレートに 実行してみると、

vbox$ ./a.out /tmp/du/*
2       /tmp/du/Makefile
46      /tmp/du/a.out
12      /tmp/du/du.1
16      /tmp/du/du.c
4       /tmp/du/du.d
38      /tmp/du/du.o

ちゃんと6個のファイルがリストされました。

存在しないファイルとかが指定されると、下記のエラーを検出する。存在しな いファイルのstatは得られないって事だ。

FTS_NS       A file for which no stat(2) information was
             available.  The contents of the fts_statp field
             are undefined.  This is an error return, and
             the fts_errno field will be set to indicate
             what caused the error.

like LinuC or LPIC

ChatGPTは難関の試験も突破する実力が有るらしい。ならばLinuxの試験 Linuxのおすすめ資格「LinuC」「LPIC」 も軽く突破 出来るに違いない。とぼけた試験官は、下記の様な面接試験を行ないました。

引数の与え方によってエラーになる場合があります。原因は何ですか? どの様に修正したらよいですか?

エラーの原因は、Haskellのプログラムではディレクトリのワイルドカード展開が自動的に行わ
れないことです。シェルで/meet/WEB/*と入力すると、シェルが*を対応するファイルやディレ
クトリに展開してduコマンドに渡してくれますが、Haskellのプログラム内ではこの展開が行わ
れないため、/meet/WEB/*という文字列そのものがduコマンドに渡され、そのディレクトリが存
在しないためエラーが発生しています。

Haskellのプログラム内でもワイルドカードを展開させるためには、System.Processモジュー
ルのshell関数を使用します。これにより、シェルにコマンドを渡してシェルの展開を利用でき
ます。

以下のように修正することで、シェルから入力した結果を欲しい通りの形で表示することができます。

-- モジュールのインポート
import System.Process
import System.IO (hGetContents)

main :: IO ()
main = do
    putStrLn "ディレクトリのパスを入力してください:"
    dirPath <- getLine
    (_, Just hout, _, _) <- createProcess (shell $ "du -sh " ++ dirPath) { std_out = CreatePipe }
    result <- hGetContents hout
    putStrLn result
    
これで、Haskellのプログラム内でシェルの展開が実行されるようになります。./du_haskellと
入力した場合には、シェルのワイルドカード展開が動作し、期待通りの結果を得ることができます。

早速実行してみる。

[sakae@arch hdu]$ ./a.out
ディレクトリのパスを入力してください:
/tmp/hdu/*
4.0M    /tmp/hdu/a.out
4.0K    /tmp/hdu/Du.hi
4.0K    /tmp/hdu/Du.hs
12K     /tmp/hdu/Du.o
4.0K    /tmp/hdu/Makefile

ちゃんとduに与えるスイッチを質問内容から組み取って提示してきた。Linux の初心者の域を軽く越えてるね。

Arrow

前回やったhasktagsの中に、こんなのが有った。何これ?

import           Control.Arrow              ((***))

extractOperator :: [Token] -> (String, [Token])
extractOperator ts@(Token "(" _ : _) =
    foldr ((++) . tokenString) ")" *** tail' $ break ((== ")") . tokenString) ts
extractOperator _ = ("", [])
ghci> :t (***)
(***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')

モナド崩れっぽく感じるんだけど。

Arrowを理解する

search

資料収集の本を読んでいたら、まずは本でしょって事で、国会図書館があげら れていた。次は公立図書館ね。

ネット住民は、 J-STAGE とかで検索してDLするのが普通らしい。いわゆる業界物ね。

情報処理に的を絞るなら、最初からそこに行くのが楽だ。

情報処理学会電子図書館

最新のものは、登録しないと手にはいらない。あるいは有料だったりする。け ど、いわゆる古本は、ほとんど無料だ。年金生活者には、強い美方だったりし ます。こんなの知らなかったなあ。

Egison

プログラミング言語 Egison

cabalでインストールしようとしたら、途中でエラーになった。ならばstackだ な。ghc 8.10 なんていう古いやつでコンパイルするのか。それにしても、CPU 負荷がメチャクチャ高くなるなあ。自己発熱で自爆しないように、半年持ち越 しする事にした。なけなしのパソコンですからね。

一体型PCのおすすめ人気ランキング12選

ミニPC

眼にやさしい大画面のパソコンが狙い目かな。メモリーは最低16G必要。これ がmustな条件。

at debian(32Bit)

これだと、メモリーがたっぷりある。朝の涼しい時に挑戦。tar玉を展開して おいて、次のコマンドを投入。

[sakae@deb egison-4.1.3]$ stack init
Looking for Cabal or package.yaml files to use to initialise Stack's
project-level YAML configuration file.                                          
Using the Cabal packages:
 * ./

Selecting the best among 20 snapshots...


Warning: Partially matches
         https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/
master/lts/21/3.yaml

             sweet-egison not found
                 - egison requires ==0.1.1.3
             text version 2.0.2 found
                 - egison requires >=0.2 && <1.3
             vector version 0.13.0.0 found
                 - egison requires >=0.12 && <0.13


Warning: Partially matches
         https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/33.yaml

             sweet-egison not found
                 - egison requires ==0.1.1.3

                 :
Note: Matches
      https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/28.yaml

Selected the snapshot
https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/28.yaml.
Initialising Stack's project-level YAML configuration file using snapshot
https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/28.yaml.
Considered 1 user package.
Writing configuration to stack.yaml.
Stack's project-level YAML configuration file has been initialised.

これがstackを使う醍醐味か。勝手にGHCの環境を調査して、問題無さそうな ghc versionを決定してくれる。結構昔の奴が選ばれた。後は、stack install するだけ。

試運転する。

[sakae@deb egison-4.1.3]$ egison
Egison Version 4.1.3
https://www.egison.org
Welcome to Egison Interpreter!
> def twinPrimes :=
    matchAll primes as list integer with
      | _ ++ $p :: #(p + 2) :: _ -> (p, p + 2)
> (take 10 twinPrimes)
[(3, 5), (5, 7), (11, 13), (17, 19), (29, 31), (41, 43), (59, 61), (71, 73), (101, 103), (107, 109)]

双子素数を見付けるサンプル。

ポーカーの役判定。この他には中国語牌の判定もあった。こんなの普通に記述 したら、どうなるんだろう?

(poker [Card Spade 5, Card Diamond 10, Card Spade 7, Card Club 5, Card Heart 8])  -- One pair
(poker [Card Spade 5, Card Diamond 10, Card Spade 7, Card Club 5, Card Heart 10])  -- Two pair
(poker [Card Spade 5, Card Spade 6, Card Spade 7, Card Spade 8, Card Spade 9])  -- Straight flush

ひとつ注意がある。stack install しても、~/.local/bin/egison* が登録され るだけ。実行に必要なそれ以外のものはインストールされない。よって、 stack install した残骸は、そのまま残しておく事。

[sakae@deb 8.10.7]$ pwd
/home/sakae/src/egison-4.1.3/.stack-work/install/i386-linux/a...f881/8.10.7
[sakae@deb 8.10.7]$ tree
├── bin
│   ├── egison
│   └── egison-translate
├── doc
│   └── egison-4.1.3
│       └── LICENSE
├── lib
│   └── i386-linux-ghc-8.10.7
│       ├── egison-4.1.3-4mHFJtnMSBEF2PJtpLq6vj
│       │   ├── Language
│       │   │   ├── Egison
│       │   │   │   ├── AST.dyn_hi
│       │   │   │   ├── AST.hi
:       :
│       └── libHSegison-4.1.3-4mHFJtnMSBEF2PJtpLq6vj-ghc8.10.7.so
├── pkgdb
│   ├── egison-4.1.3-4mHFJtnMSBEF2PJtpLq6vj.conf
│   ├── package.cache
│   └── package.cache.lock
└── share
    └── i386-linux-ghc-8.10.7
        └── egison-4.1.3
            └── lib
                ├── core
                │   ├── assoc.egi
                │   ├── base.egi
                │   ├── collection.egi
                :

etc