関数型プログラミングの考え方を理解するための昔の記事
この前
関数型プログラミングはまずは純粋関数型言語を用いて、考え方から理解しよう
関数型プログラミングはまず考え方から理解しよう - 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 とかで調べないといけないのかな。
Googleアナリティクス4プロパティで使われているフロントエンドのツール
メインのプログラムは<script id=base-js ・・・となっている場所にある。
あとはHTMLやJSのcopyrightなどを見ていく。
依存関係は知らないので(angularを使えばlessとmaterialは勝手に付いてくるよ!など)見つけた順に書いていく。
- Closure Library
- Closure Compiler
- Less 1.7.5 https://lesscss.org/
- Material Design https://material.io/
- jQuery 2.2.5-pre
- AnglarJS 1.6.4 https://angular.io/
- d3 https://github.com/d3/d3
- Papa Parse 4.1.2
- RxJS
- MochiKit (Closure Library)
- Polymer https://github.com/Polymer/polymer (?)
- Math.uuid.js 本家消滅? https://gist.github.com/Wind4/3baa40b26b89b686e4f2
- https://fonts.google.com/
今までと大きな違いは無い感じ。
Angular用の細かいライブラリは省略。
StackでHaskellの環境を作れなかったログ
今のPCにGHCが無かったので入れた。
どうやって環境を作ったのか忘れていて、どこかに書いた気がするけど見つからないのでメモ。
うーん…stackの一通りの使い方とか、前にも書いた気がするんだが…。GHCJSのことを書いて肝心のGHCのことは書いてなかった?
sudo apt-get install g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev git gnupg netbasehttps://docs.haskellstack.org/en/stable/install_and_upgrade/#linux
今の環境だと全てインストールされていたので実行する必要はなかった。無い場合は入れる。
https://get.haskellstack.org/stable/linux-x86_64.tar.gz
バイナリを取ってきて ~/bin/ 等にコピー。
最初のhello worldを実行。
stack new helloworld new-template cd helloworld stack build
まだ環境が何もないのでダウンロードが始まる。 ~/.stack/ に環境が作られる。
ghc-modをインストール。
stack install ghc-mod
エラーでインストールできない。
Failing to build ghc-mod with stack · Issue #940 · DanielG/ghc-mod · GitHub
~/.stack/global-project/stack.yaml でLTSのバージョンを変える。
resolver: lts-9.21
ちょっとバージョンが古くなってしまったけれど、これでいけた。
stack install intero
次はintero-modeが動かない。
intero-modeのページにも、別のツールを使えと書いていた。
ghc-modのページにも、古いから haskell-ide-engine を見ろと書いていて、haskell-ide-engine のページには haskell-language-server を見ろと書いていた。カオス。あんまり複雑なのは嫌なんだけど…。
https://n314.hatenablog.com/entry/2019/06/01/191056
ここで色々やったみたい。うーん諦めて新しい方のツールを入れるべきか。
TCPDFで円とベジェ曲線で図形を描く
TCPDFでちょっとした図形を入れたい場合、画像を使わずに直接PDFに出力してしまう方法がある。
TCPDFのソースとマニュアルを見ていたらベジエ曲線が簡単に描けるようなのでやってみた。
(ベジェ曲線?どっち?昔聞いたときはベジエ曲線と発音されていたような気がする。)
まずは円弧を描く。
<?php // (snip) $x = $pdf->GetX(); $y = $pdf->GetY(); $w = 20; $h = 20; $cx = $x + $w / 2; $cy = $y + $h / 2; $cw = $w / 2; $start = 0; $end = $start + 255; $pdf->Circle($cx, $cy, $cw, $start, $end, 'D');
角度は右が0度で半時計回りに指定するようだ。
これで右から255度分の円弧を描ける。
ベジエ曲線は、開始座標+3座標を指定する。
<?php // (snip) $ax = $cx + $cw * cos(deg2rad($end)); $ay = $cy - $cw * sin(deg2rad($end)); $aw = $x + $w - $ax; $ax1 = $ax + $aw / 2 * $sign; $ax2 = $ax + $aw * $sign; $ax3 = $ax + $aw * $sign; $ay1 = $ay; $ay2 = $ay + $w / 3; $ay3 = $ay + $w / 2.5; $p1 = [$ax1, $ay1, $ax2, $ay2, $ax3, $ay3]; $pdf->Polycurve($ax, $ay, [$p1], 'D');
円弧の端の座標をsinとcosで求める。
角度は$endをラジアンに変換する。deg2radっていう組み込み関数があったんだね。
そこからなめらかになるように、座標を配列で指定して Polycurve 関数で出力する。[$p1]となっているところは、複数繋げると複雑な曲線が描ける。
こんな感じに線を引けた。
中を塗る場合は、反転したベジエ曲線切らずに繋げて空白を埋めるように工夫する必要がある。
<?php require_once 'vendor/autoload.php'; function drawCircle($pdf, $reverse) { $x = $pdf->GetX(); $y = $pdf->GetY(); $w = 20; $h = 20; $cx = $x + $w / 2; $cy = $y + $h / 2; $cw = $w / 2; $start = 0; $end = $start + 255; $pdf->Circle($cx, $cy, $cw, $start, $end, 'D'); } function drawBezier($pdf, $reverse) { $x = $pdf->GetX(); $y = $pdf->GetY(); $w = 20; $h = 20; $cx = $x + $w / 2; $cy = $y + $h / 2; $cw = $w / 2; if (!$reverse){ $start = 0; $end = $start + 255; }else{ $start = 285; $end = 180 + 360; } if (!$reverse){ $sign = 1; $point = $end; }else{ $sign = -1; $point = $start; } $ax = $cx + $cw * cos(deg2rad($point)); $ay = $cy - $cw * sin(deg2rad($point)); if (!$reverse) $aw = $x + $w - $ax; else $aw = $ax - $x; $ax1 = $ax + $aw / 2 * $sign; $ax2 = $ax + $aw * $sign; $ax3 = $ax + $aw * $sign; $ay1 = $ay; $ay2 = $ay + $w / 3; $ay3 = $ay + $w / 2.5; $p1 = [$ax1, $ay1, $ax2, $ay2, $ax3, $ay3]; $pdf->Polycurve($ax, $ay, [$p1], 'D'); } $pdf = new TCPDF(); $pdf->AddPage(); $pdf->SetFont('genshingothic', '', 8); $color = [255,100,100]; $pdf->SetFillColor(...$color); $pdf->SetDrawColor(...$color); $pdf->Cell(0, 0, '円弧を描く', 0, 1); drawCircle($pdf, false); $pdf->SetY($pdf->GetY() + 30); $pdf->Cell(0, 0, '円弧を反転してもう一つ描く', 0, 1); drawCircle($pdf, false); $pdf->SetX($pdf->GetX() + 20); drawCircle($pdf, true); $pdf->SetY($pdf->GetY() + 30); $pdf->Cell(0, 0, 'ベジエ曲線を描く', 0, 1); drawCircle($pdf, false); drawBezier($pdf, false); $pdf->SetY($pdf->GetY() + 30); $pdf->Cell(0, 0, '円弧とベジエ曲線を反転して描く', 0, 1); drawCircle($pdf, false); drawBezier($pdf, false); $pdf->SetX($pdf->GetX() + 20); drawCircle($pdf, true); drawBezier($pdf, true); $pdf->Output();
Debian busterにmxeをインストールしてQtCreatorで使う
Mastering Qt 5 の Chapter 2 で、いきなり windows.h が要求されて詰まった。ハードル高くない?スルーしてLinuxのコードの部分だけやればいいのかもしれないけど、もやもやする。
そもそもQtを使う人は様々なOSで使いたいわけだから、最初の方のchapterに複数OSの対応を書いておくのが良いということかな。
あまり詳しい説明はないままWindows、Linux、Mac用のコードが書いてある。それぞれのPCで各自環境構築はやってねということか。OSはあることはあるけど、いちいちソースを移動するのは面倒だよね。それぞれに開発環境を入れないといけないし。
仕方がないのでwindowsバイナリをコンパイルできるように設定する。
まず、mxeを取ってきておもむろにmxeをmakeする。
git clone https://github.com/mxe/mxe.git cd mxe make qt5
missing ... と表示された場合は、足りないものを https://mxe.cc/#requirements を見ながらインストールする。
(aptコマンドをコピペしても良いが、一応一つ一つ確認しながらインストールしたいので)
今の自分の環境だと以下のパッケージが必要だった。
apt install bison flex gperf intltool-bin libtool lzip
あとは
make -j10 MXE_TARGETS='x86_64-w64-mingw32.static' qt5
してしばらく待つ。
結構時間がかかる。(-j オプションと64bitターゲット指定を忘れないように)
# 4/27 追記
身内だけで使うならこれでもいいけど、公開するなら
make -j10 MXE_TARGETS='x86_64-w64-mingw32.shared' qt5
shared の方が良いかも。
まあ配布するなら、配布用バイナリはWindowsでコンパイルする方が良いのかもしれないが。
あと、そもそもqtcreatorをwineで入れる方法があるようだ。
Cross compiling Qt application for Windows on Linux with dynamic linking - Stack Overflow
こっちはちょっと面倒かな。それなら仮想マシンのWindowsにqtcreatorを入れる方が楽な気がする。
# 4/28 追記
mxe で sharedのバイナリは起動できなかった。
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Unhandled exception: unimplemented function KERNEL32.dll.RaiseFailFastException called in 64-bit code (0x000000007bc5d60c). Register dump:
というエラーが出て、ログには
wine: Call from 0x7bc5d60c to unimplemented function KERNEL32.dll.RaiseFailFastException, aborting wine: Unimplemented function KERNEL32.dll.RaiseFailFastException called at address 0x7bc5d60c (thread 0009), starting debugger...
というエラーが出ている。他にも
0025:err:winediag:xrandr12_init_modes Broken NVIDIA RandR detected, falling back to RandR 1.0. Please consider using the Nouveau driver instead. 002b:fixme:dbghelp:elf_search_auxv can't find symbol in module
のエラーが出ていた。NVIDIAのエラーは、正常に動く場合でも出てる。
仕方がないので普通にWindowsにVisual Studio 2019 と Qt を入れた。
# 追記ここまで
コンパイルが終われば、QtCreatorの「オプション」「Kits」の設定で
コンパイラ
Cコンパイラ:mxe/usr/bin/x86_64-w64-mingw32.static-gcc
C++コンパイラ:mxe/usr/bin/x86_64-w64-mingw32.static-g++
CMake
mxe/usr/bin/x86_64-w64-mingw32.static-cmake
Qtバージョン
mxe/usr/x86_64-w64-mingw32.static/qt5/bin/qmake
キット
上記設定したものを指定
適当にMinGWとでも名前を付けてPATHを手動追加する。
コンパイラのABIは x86 windows msys pe 64bit にする。
chapter 02 をある程度進めて、Windows版はビルドしてから wine64で立ち上げる。
これでいいのかな?とりあえずCPU Widgetは Linux版もWindows版もDebian上で確認できた。
Qtをやってみてる
Qt Creatorをインストールする。
apt install qtcreator
他にも何か入れたかもしれない。Qt Creatorを使わずに qmake だけ入れたこともあって、そのときのライブラリが残っているのかもしれない。忘れた。
デバッグでエラーが出るのでpython で gdbが使えるようにしておく?
The selected build of GDB does not support python scripting. It cannot be used in Qt Creator.
デバッグ実行するとこのエラーが出る。
gdbは入っているのになと思っていたら、gdb-minimalではダメで
apt install gdb
する必要があったようだ。
Debugger does not start. GDB not support Python scripting. | Qt Forum
python-dbg は要らなかった。
そうすると起動はしたけどwarningが出る。
&"warning: GDB: Failed to set controlling terminal: \343\203\207\343\203\220\343\202\244\343\202\271\343\201\253\345\257\276\343\201\231\343\202\213\344\270\215\351\201\251\345\210\207\343\201\252ioctl\343\201\247\343\201\231\n"
printf "warning: GDB: Failed to set controlling terminal: \343\203\207\343\203\220\343\202\244\343\202\271\343\201\253\345\257\276\343\201\231\343\202\213\344\270\215\351\201\251\345\210\207\343\201\252ioctl\343\201\247\343\201\231\n" | nkf warning: GDB: Failed to set controlling terminal: デバイスに対する不適切なioctlです
c++ - Setup GDB with QtCreator - Stack Overflow
ターミナルで実行すれば解決するみたいだけど、いちいちターミナルを開くのは見づらいかもしれない。
とりあえずスルーで。
これでMastering Qt 5を写経してみている。
英語だけれど意外と読める。
英語の児童小説は1ページも読めなかったけれど、プログラムの本なら読めるというのが新感覚。
時々英語のAPIドキュメントとかチュートリアルとか見てるおかげ?文章の意味が分からなくてもプログラムの意味は分かるのが大きいのかも。Dockerのセットアップとかが英語で書かれていても、読むというよりはざっと眺める感じだし、この本もそれに近い。重要な概念の説明っぽい箇所は意味を調べつつ読んでるけれども。
Google翻訳アプリのカメラでリアルタイム翻訳が、ちょっと惜しい感じ。文章を上書きしないで単語の説明を出してほしいところだけど、カメラが揺れるし使いやすくするのは難しいのかも。
今はChapter 01 をやったところ。