ログ日記

作業ログと日記とメモ

muttを設定する

ちょっとミーハーな心持ちで、以前挫折したCLIメーラーをインストールしてみる。
一応
GnuPG を使えるメーラーを探す - ログ日記
の続き。


大量のメールを処理できるNeomutt - Solist Work Blog
ここを読んでNeomuttが気になったけど
NeomuttでGmailにOAuth2.0する - Qiita
Debian(buster) の場合はMuttよりNeomuttの方が古いっぽいので。
bullseye なら大丈夫っぽい。


muttをインストールすると

/usr/share/doc/mutt/examples/mutt_oauth2.py

があるので、どこかのbinにコピーしてくる。

python のファイルの上の方に registrations 変数があって接続情報が書かれているので、直接編集。
ENCRYPTION_PIPE にもGPGで使っているメールアドレスを書く。


/usr/share/doc/mutt/examples/mutt_oauth2.py.README を読みつつ
Mutt - ArchWiki
ここも読みながら muttrc を設定する。


先にGoogleAPIでoauthのIDを発行しておく。テスト用でいけた。


とりあえず接続テストは

./bin/mutt_oauth2.py user@example.com.tokens --verbose --authorize

のようにして質問に答えていってから

./bin/mutt_oauth2.py user@example.com.tokens --verbose --test

で確認。


muttrcでのGmailの設定は

set from="user@example.com"
set realname="User Name"
set imap_user="user@example.com"
set folder="imaps://imap.gmail.com/"
set smtp_url="smtps://${imap_user}@smtp.gmail.com:587/"
set imap_authenticators="oauthbearer:xoauth2"
set imap_oauth_refresh_command="/home/user/bin/mutt_oauth2.py /home/user/.mutt/${imap_user}.tokens"
set smtp_authenticators=${imap_authenticators}
set smtp_oauth_refresh_command=${imap_oauth_refresh_command}

このように書いた。

あとは設定を適当なサンプルから持ってきた。

set spoolfile = "+INBOX"
set imap_check_subscribed
set hostname = gmail.com
set mail_check = 120
set timeout = 300
set imap_keepalive = 300
set postponed = "+[GMail]/Drafts"
set record = "+[GMail]/Sent Mail"
set trash = "+[GMail]/Trash"
set header_cache=~/.mutt/cache/headers
set message_cachedir=~/.mutt/cache/bodies
set certificate_file=~/.mutt/certificates
set signature =~/.mutt/signature


Gmailを見れるようにはなった。
でも、使えるかと言われると…うーん。
初めてvimを起動して終了方法すら分からなかったときような感じ。


Claws MailじゃなくてSylpheedを試してみようか。

DebianでVMwareが遅い問題は解決してなかった

https://n314.hatenablog.com/entry/2021/01/28/104312
こっちの設定をやってしばらく使ってるけど、やっぱりVMwareの起動直後はkcompactd0がフルにCPUを使って3分ぐらいほとんど操作できない。

/sys/kernel/mm/transparent_hugepage/defrag の設定は madvise にしていた。これってアプリケーションが必要だからデフラグを要求してるってことだよねえ…。
VMware用にメモリを12GB設定しているから、その分のデフラグは必要だってことなんだろうか。

固まるのは起動時だけで、最初にちょっと待てば後は大丈夫なんだけど。


qiita.com
今度VMware起動前と起動後で断片化をチェックしよう。

PHPStanとPsalmを混ぜた機能が欲しい

PHPStanはテンプレート+callableのネストに対応していた。

<?php

/**
 * @template A
 * @template B
 * @template X
 * @param callable(A,B):X $f
 * @return callable(A):(callable(B):X)
 */
function f2(callable $f)
{
    return function($a) use ($f){
        return function ($b) use ($f, $a){
            return $f($a, $b);
        };
    };
}

/**
 * @template A
 * @template B
 * @template C
 * @template X
 * @param callable(A,B,C):X $f
 * @return callable(A):(callable(B):(callable(C):X))
 */
function f3(callable $f)
{
    return function($a) use ($f){
        return function($b) use ($f, $a){
            return function($c) use ($f, $a, $b){
                return $f($a, $b, $c);
            };
        };
    };
}

function str_repeat_split(string $s, int $time, string $separator):string
{
    $arr = [];
    for ($i = 0; $i < $time; $i++){
        $arr[] = $s;
    }
    return implode($separator, $arr);
}
function test(): string
{
    $f = f3('str_repeat_split');
    $g = $f('abc');
    $h = $g(1);
    // $h(1);
    $h("\n");

    $i = f2('str_repeat');
    //$j = $i('abc')('def');
    $j = $i('abc')(2);

    $k = f2('str_repeat')('abc');
    //$l = $k('def');
    $l = $k(2);

    // $m = f2('str_repeat')('abc')('foo');
    $n = f2('str_repeat')('abc')(2);
    return nl2br($n);
}

コメントを外すと正しいエラーが報告される。

ここで、括弧がちょっとめんどいので

<?php

$n = f2('str_repeat')('abc')(2);
$n = f2('str_repeat', 'abc', 2);

引数と関数呼び出しの区別を無くして、並べて呼び出せるようにしたい。

機能だけなら
github.com
昔作ったんだけど、型チェックが効かない。


PsalmのConditional return typesの機能を使ってfunc_num_argsで戻り値の型を条件分岐させたい。
でもPsalmは

 * @return callable(A):(callable(B):(callable(C):X))

みたいな複雑な型に対応してないっぽい。



github.com
PHPStanにもconditional return typesの機能を付ける話は出ているみたい。

That's what this open feature request asks for, it's on my roadmap to implement this.

issue登録者が間違ってクローズしたものを作者が再オープンしていたので、しばらく待てば実装されるんだろうか。
もうすぐ1年経ってしまうけれども。

haskell-language-server の設定2

https://n314.hatenablog.com/entry/2021/07/24/173834 の続き。

emacs lsp-mode "disconnected"」で検索した https://github.com/emacs-lsp/lsp-mode/issues/905 ここのコメントに M-x lsp してログを見ろと書いていたので、そのようにする。

lsp-haskell stack "Cradle requires ghc but couldn't find it"

という警告が出ていた。
というかそもそもEmacs起動時に

Server lsp-haskell:27768/starting exited with status exit(check corresponding stderr buffer for details). Do you want to restart it? (y or n)

というエラーも出ていた。

検索して出てきた
haskell-language-server+emacsでのハマりどころ2020年夏
このページを見てもよく分からなかったけど、そういえば hie.yaml が必要だったとどこかに書いていた記憶がある。
手動で作ってうまくいかなくて消したんだった。


hie.yamlでもう一度調べる。
(廃止) VS Code と haskell-ide-engine で Haskell 開発環境を構築する
Haskell環境構築2020簡易版 (macOS, Linux向け) - LugendrePublic

stack install implicit-hie
gen-hie > hie.yaml

そして stackプロジェクトのMain.hsを起動。

emacs app/Main.hs &

おおお、いけたじゃん!


あとは修正と設定。

Error running timer ‘lsp--on-idle’: (wrong-type-argument integerp 9.223372036854776e+18)

というエラーが出るのを回避する。
https://github.com/emacs-lsp/lsp-mode/issues/2435

(setq lsp-headerline-breadcrumb-enable nil)
Error while checking syntax automatically: (error "Keyword argument :end-line not one of (:buffer :checker :filename :line :column :message :level :id :group)")

というエラーが出るのでflycheckをバージョンアップ。



型を自動で挿入したいので

(defun lsp-haskell-execute-code-action-add-signature ()
  "Execute code action of add signature.
Add the type signature that GHC infers to the function located below the point."
  (interactive)
  (let ((action (seq-find
                 (lambda (e) (string-prefix-p "add signature" (lsp:code-action-title e)))
                 (lsp-code-actions-at-point))))
    (if action
        (lsp-execute-code-action action)
      (message "I can't find add signature action for this point"))))
https://www.ncaq.net/2021/06/25/18/20/30/

これを何かのキーに割り当てる。

オプションで

{-# OPTIONS_GHC -Wmissing-signatures #-}

を設定してwarningが出るようにしておく必要があるっぽい。


あとは定義ジャンプ。
Emacs で Language Server Protocol を使ってみる :: プログラマになりたい人生 — プログラマになりたいおじさんの日記



右に色々出たりコードに線が出るけど、まだあまり意味が分かっていない。
Fold とか Unfold は何なんだろう…?IDEで関数を閉じたりする?haskell-modeでは使わない?
Use pointとかreduceとかは押したら文字が削られる…。
How do you use (un)folding? · Issue #418 · haskell/haskell-language-server · GitHub
よく分からん…。
他にも、haskellではなくてlsp-modeのreadmeを見た方がいいかも。



7/31 追記:

Main.hs is not part of any project. Select action:

i==>Import project root path/to/project/
I==>Import project by selecting root directory interactively.
d==>Do not ask again for the current project by adding /path/to/project to lsp-session-folders-blacklist
D==>Do not ask again for the current project by selecting ignore path interactively.
n==>Do nothing: ask again when opening other files from the current project.

というメッセージがミニバッファに出る場合は i を押す。
一瞬で消えたりするので、他のキーを触らずに i を押す。M-x lsp でもう一度見れる。

もしかして以前やったときはこのメッセージを見逃していたのかもしれない。


あと、他のファイルに飛べない?
xref-find-definitions で Main.hs から Lib.hs に飛べない。

と思ったけど、Lib.hs と同じ階層にFoo.hsを作ったらそこには飛べる。
stack new したプロジェクトの構成が分かってないのが問題か…。

Haskellのstackによるプロジェクトについて - Qiita
コメントも参考になる。

Stackでやる最速Haskell Hello world! (GHCのインストール付き!) - Qiita
チュートリアル

Emacsのplantuml-modeのpreviewで日本語が文字化け

別のPCで設定したらPlantUMLのプレビューで日本語が出なくなっていて、放置していた。
コマンドなら問題なかったので、Emacsがどういうコマンドオプションで呼び出しているのかをシェルスクリプトでprint debugして調べて、手動で実行してみる。

cat foo.plantuml | /path/to/bin/plantuml -headless -tsvg -p > foo.svg

svgに問題はなかった。
でもこのsvgEmacsで開くと文字化けする。
Emacsのimage-modeの設定?
昔の環境だとsvgではなくpngでプレビューしてたのかな。

どこかに設定があるはずだと思って設定方法を探す。
GitHub - skuro/plantuml-mode: A major mode for editing PlantUML sources in Emacs
よく分からんかったのでplantuml-mode.el のソースを見て調べた。

(setq plantuml-output-type "png")

これでプレビューの日本語が出るようになった。

関数型プログラミングの考え方を理解するための昔の記事

この前
関数型プログラミングはまずは純粋関数型言語を用いて、考え方から理解しよう
関数型プログラミングはまず考え方から理解しよう - Qiita
ここを読んだ。

関数型プログラミングの考えを学ぶには、純粋関数型言語で学ぶべきである

これは同意なんだけど、サンプルコードがしっくり来ない。


こんなに複雑になる?というかオブジェクト指向のコードを関数型っぽく変換ということに無理があるような。
仕様を満たすコードをゼロから考えたら、全然変わってくるような。

ということでちょっとHaskellで書いてみた。

data Dish = Karaage deriving Eq
data Bento = Bento Dish Int deriving Eq

単純な数値のリストかタプルでもいいんだけど、オブジェクト指向に寄せてデータ構造を書く。

eat :: Bento -> Bento
eat (Bento s a) = Bento s (a - 1)

replaceList :: Bento -> [Bento] -> [Bento]
replaceList m a = replace a
  where
    replace [] = []
    replace (x:xs)
      | m == x = eat x:xs
      | otherwise = x:replace xs

「データを1減らす」という処理と「リストを一つ入れ替える」という処理を書く。
「リストから最大のものを1件探す」という処理は maximumが使えるので、そのまま使う。

それからユーティリティ的な関数、「xに関数fをn回適用した結果を返す」を作る。

nest :: (a -> a) -> a -> Int -> a
nest f x n = (iterate f x) !! n


最後に

bentoList :: [Bento]
bentoList = [Bento Karaage 10, Bento Karaage 8, Bento Karaage 6]

main :: IO ()
main = putStrLn $ show $ nest (maximum >>= replaceList) bentoList 5

一気に関数を接続して、計算。
※ n回繰り返したときの処理ログが欲しいわけではなく、最後の結果が欲しいということだと読み取ったので、途中経過は出力しない。


関数型プログラミングっていうかHaskell独自のことかもしれないけど、とりあえず細かい関数のパーツを作っておいて、繋ぎ合わせて大きな機能を作るのが関数型プログラミングの考え方っぽいと思える。



昔見たブログのやり取りはとても良かった。
Haskell でグローバル変数が欲しい理由 - あどけない話
グローバル変数が欲しい理由?http://web.archive.org/web/20100702191552/http://www.sampou.org/cgi-bin/haskell.cgi?%A5%B0%A5%ED%A1%BC%A5%D0%A5%EB%CA%D1%BF%F4%A4%AC%CD%DF%A4%B7%A4%A4%CD%FD%CD%B3%A1%A9
「グローバル変数が欲しい理由?」の考察 - あどけない話
URLが変わっちゃったので再度メモ。





以下全体のコード。

module Main where

data Dish = Karaage deriving Eq
data Bento = Bento Dish Int deriving Eq

instance Show Dish where
  show Karaage = "唐揚げ"
instance Show Bento where
  show (Bento a b) = show a ++ show b ++ "個"
instance Ord Bento where
  compare (Bento Karaage a) (Bento Karaage a') = compare a a'

nest :: (a -> a) -> a -> Int -> a
nest f x n = (iterate f x) !! n

eat :: Bento -> Bento
eat (Bento s a) = Bento s (a - 1)

replaceList :: Bento -> [Bento] -> [Bento]
replaceList m a = replace a
  where
    replace [] = []
    replace (x:xs)
      | m == x = eat x:xs
      | otherwise = x:replace xs

bentoList :: [Bento]
bentoList = [Bento Karaage 10, Bento Karaage 8, Bento Karaage 6]

main :: IO ()
main = putStrLn $ show $ nest (maximum >>= replaceList) bentoList 5

haskell-language-server の設定の途中

https://n314.hatenablog.com/entry/2021/07/20/203555 の続き。



https://haskell.e-bigmoon.com/hie/emacs.html
https://haskell.e-bigmoon.com/posts/2020/07-12-haskell-language-server.html

git clone https://github.com/haskell/haskell-language-server.git
cd haskell-language-server
# stack ./install.hs hls
stack ./install.hs hls-8.10.4

GHCバージョンが新しくなりすぎないように、バージョンを指定する。stack ./install.hs help で見れる。
8.10.4 は resolver: lts-17.12 ?


emacsのパッケージでエラーが出るので
https://github.com/emacs-lsp/lsp-java/issues/142
ここに書いている通り

("gnu" . "http://elpa.gnu.org/packages/")

を加える。
melpa の stable は除外した。

package-install でlsp-mode、lsp-ui、lsp-haskellをインストール。エラーが出るので dash も入れる(更新?)。


C-c C-l でstackを使う設定。
https://qiita.com/t-mochizuki/items/d831df3a920108e2d83c


~/.stack/config.yaml に allow-newer: true を付けて stack install cabal-install する。




・・・

最新版で入れ直したり色々やったけど、LSP[Disconnected] になってる。
うーん分からん…。
とりあえず、エラーは出るしC-c C-l も出来るようになったんだけど、型注釈の補完ができない。あとエラーをいい感じに表示する方法が分からない。
これはlsp-haskellで調べずに、lsp-mode とかで調べないといけないのかな。