2025年11月8日土曜日

Qtのandroidへのデプロイ(備忘録)

 android studioをインストール
環境変数 setxで永続保存
setx JAVA_HOME "C:\Program Files\Android\Android Studio\jbr"
setx ANDROID_SDK_ROOT  "C:\Users\<ユーザー名>\AppData\Local\Android\Sdk"
setx ANDROID_NDK_ROOT  "C:\Users\<ユーザー名>\AppData\Local\Android\Sdk\ndk\29.0.14206865" のように
NDKがないときインストール必要(CMAKEも)
Qtで プロジェクト>キットの管理...>デバイスでAndroidが追加できるが、他の項目をチェックしてまだ不十分なところ(SDKsの赤字のところSdkCommandLineToolなどあれば)をAndroidStudioのSDK Managerで設定していく
・OpenSSLダウンロードなども

スマホ側設定:「設定 → 開発者向けオプション」を有効化→ 「ビルド番号」を7回タップして出ます。「USBデバッグ」をオンにする システムの開発者向けオプションの設定で

PC側:Android Studio で「SDK Manager → SDK Tools → Android SDK Platform-Tools」
がインストールされていること(=adbコマンドが使える)。Qt Creator が SDK/NDK/JDK を認識している。(ツール → オプション → Devices / Android を確認) 

デプロイ手順(Qt Creatorから):スマホをUSBで接続>
adb devices→ device と表示されれば接続成功。
(C:\Users\<ユーザー名>\AppData\Local\Android\Sdk\platform-tools\adb.exeのパスも通しておく必要あり、コントロールパネルあたりから)
Qt Creator を開く>左下でデバイスとしてスマホ選択>▶ 実行ボタンをクリック
Qt が自動で.apk をビルドスマホへインストール>アプリを起動

ビルド、デプロイ環境構築に手間はかかるが、自作アプリがWin、Linuxだけでなくスマホでも使えるのは便利。

QtのWindowsでのデプロイ方法

 マルチプラットフォーム言語のため、デプロイ方法は少し手間がかかる。

mingwの形式でビルドした場合

Release ビルドの exe があるディレクトリに移動して、

cd C:\Users\****\kjog\build\Desktop_Qt_6_9_3_MinGW_64_bit-Release

windeployqt.exe のフルパスを指定して実行する必要がある。

"C:\Qt\6.9.3\mingw_64\bin\windeployqt.exe" kjog.exe

2025年11月1日土曜日

ESP32 DEVKIT_Cで容量をWIFIでロギング

間欠動作で12時間ごとにGPIO4を容量センサとして使い、ロギングしてみた。raspiにGETでデータを保存し、スマホ等で取り出すアプリを作れば完成の予定。 はたして、灯油タンク残量が容量センサで計測実用なるか、テスト予定。(PICのCPSも検討したが、かえって複雑になりそうなので、このパターンにしてみた。)
PICに比べると、至れり尽くせりでesp32は開発しやすい。それでも、ネットワークがからむとプロトコルやポートとかいろいろ調整が必要になってくる。

2025年10月30日木曜日

PIC12F1822で間欠ブザー

30秒ごとにブザーならすタイマーをPICで作ってみた。TTP223と2sc1815で電源オンオフ、電子ブザーはPICのRA2で出力してみた。電源はボタン電池で常時TTP223を待機状態にしておくけれど、ほとんど消費しないらしいので、これで試してみたい。なお省エネのため、TTP223のLEDは取り外した。かわりにブザーを1secごとに1msならして、電源状態確認できるようにした。
 
 最初、TTP223がオフの状態でもブザーがかすかに音するので、なぜかと思ったら、PICのアースはコレクタに、ブザーのアースは電源のアースにつないでいたためだった。内部抵抗による微妙な電位差が原因かと思われます。
 PICとブザーのアースをどちらもトランジスタのコレクタにつなぐことで解決した。


2025年10月29日水曜日

PIC12F675のタイマー修正

 以前つくったタイマーのコード修正してみた。すでにPICを基板に半田づけしてしまったが、PicKITに合わせてコネクタをつけてPICにエナメル線で配線しなんとか、書き込みできるようにしてみた。コードを少し変更して、時間ずれも調整してみた。1割ほど時間が短いので、11/10をかけてみた。だいぶ正確になる。


2025年10月28日火曜日

PIC12F1822のCPS 再挑戦

 静電気測定ということで、PICのCPSを内臓クロックで使ってみたが、温度の影響のためか、変動が大きい気がしたので、12MHzのXtalを使ってみた。ヤフオクで、10pfコンデンサと一緒に購入。


・配線は混乱してきたので、基板を新しくして配線しなおす。
・RA4とRA5をXtalにつなぐため、CPSはRA0に変更したり、周波数も変わるため、ANSELA、TRISA,CPSCON1,SSP1ADDなどの設定を慎重に変更する必要があった。
・XtalをRA4とRA5に接続したら、この2か所に2個10pFをつないでアース。
・TTP223は消費電力が少ないようなので、電池に常時つないで、トランジスタスイッチを動作させることにした。2sc1815使用。電源はエネループ3本。

 タッチしたときだけ、LCDが表示されるようになった。以前は、ボタンスイッチの接触不良があって使いにくかったが、これだとストレスなく使える。
・当初、灯油残量センサに使う予定だったが、ESP32だけで間に合いそうだったので、最終的には容量測定器にしてみた。pF=60000/cps-0.02*cpsという近似式を使ってみた。30pF~20000pFぐらいの範囲で、ある程度の目安としては使えることを確認した。本来反比例になるはずだけれど、容量が小さくなると誤差が出やすくなるようで、-0.02*cpsで補正。

2025年10月26日日曜日

Qtで、UIデザイナでMainWIndowにWidgetを配置する

 C#とは、コントロール(Widget)の配置の仕方が違うので少しとまどいました。

別ウインドウに表示はしやすいのですが、メインウインドウ内に配置するには、レイアウトの指定が必要なようです。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    table = new KakeiboTable(); // 親は addWidget() で設定されるので不要
    ui->centralwidget->layout()->addWidget(table);
}

上記コードだけでは、エラーになります。centralwidgetにテーブルビューを配置したい場合は、cetnralwidgetをオブジェクトインスペクタで選択したら、メニュー>フォームエディタから、レイアウトの方法を指定する必要がありました。ここらへんは、Qt独特のところで慣れが必要なところかもしれません。

あとはmain.cppで
    MainWindow *w = new MainWindow();
    w->show(); 
とするだけで、Widgetが配置されたメインウインドウを表示できます。

2025年10月22日水曜日

Git復習

cloneせずに、zipから展開してwinPCでQtをビルドしたりしたので、gitの整合性がとれずとまどう。(こういうときはcloneするのが基本かも)

今回のようにしてしまったら、修正には、ちょっと手間がかかる。
stash → 作業中の変更を一時退避して安全にする
fetch → リモートの最新履歴を取得
reset --hard → ローカルの土台をリモートに合わせる
stash pop → 退避していた変更を土台の上に戻す
commit → 作業を正式にコミット
push → 安全にリモートに反映
まだ、gitよくわかってないところも多いけれど、失敗しながら慣れていくしかないようだ。

Qtのクロスプラットフォームでの開発 覚書

 github経由で、winでもlinuxでもコードを開発できるようにするには

安全なクロスOS運用の基本手順
git fetch                # 最新のリモート状態を確認
git pull                 # ローカルブランチに統合(最新化)
# ↓ コード修正(Linux/Windowsどちらでも同じ)
できたらpush

🔹 注意点
改行コードや文字コードの吸収
Git: .gitattributes に * text=auto
Qt: Qt::endl / QTextStream を使う
pull前にfetchで確認

2025年10月20日月曜日

QtCreatorをLinux Mintにいれてみた ~Flatpakについての覚書~

Flatpakでインストールした場合、サンドボックス化されているため、ショートカットを自分で作成することになるようです。 

Flatpak ショートカット作成の基本フロー:

①flatpak listでApplication ID を確認  例: io.qt.QtCreator

②#!/bin/bash

flatpak run io.qt.QtCreator を作成し、実行権限不可

③デスクトップショートカット作成ならば .desktop ファイルの Exec= にスクリプトや flatpak run <アプリID> を指定

Exec=flatpak run io.qt.QtCreator

2025年10月18日土曜日

IC-705のAMラジオ用アンテナ

 手軽にAMラジオをIC-705で聞けないか、フェライトバーアンテナを試してみた。今、入手が難しくなっているらしいけれど、ヤフオクでラジオから取り外したと思われるものをたまたま見つけて290円で落札させていただいた。1次側が670uHほどだったので、共振周波数から容量を計算すると中波なら40pF前後を並列につなぐ必要がある。たまたま半固定の小型バリコンがあったので、2個並列でつないで、2次側を無線機のアンテナ側につなぐ。窓のそばで位置やバリコンを調整すると、59+20dBと、十分な感度。意外とフェライトバーアンテナのゲインは高いようだ。 

アクリル板のケースに収めて小型アンテナにすることができた

 MLAと理屈は同じようで、調べてみると、高Qで帯域外ノイズを除去、電界ノイズに鈍感(磁界のみ検出) といった効果があるとか。

2025年10月15日水曜日

VY24G/D i5-520MにLinux Mint

 i5-520Mは第一世代で、Win11も23H2までは、SSD化や4GBメモリで騙しだましつかってきましたが、さすがに25H2は、かなり無理がありそうだったので、諦めてLinuxを試すことに。ところが、標準インストールだとなかなかうまくいきません。しばらくして、原因がつかめました。

・BIOSでUSBメモリ選択では、読み取れずUSB HDD選択で読み取れました。(DVDでは遅すぎて無理があります。USBメモリを使いましたが、なぜかUSB HDDを選択しないとだめでした。)

・標準インストールだと最近のLinuxはほとんどGPTのため、うまくいきません。事前にMBR(msdos)に変更が必要です。ここが一番のネックのようです。

 Linux Mint ,MX Linuxあたりに候補をしぼりましたが、最終的にMint xfceにしてみました。Windowsと配置が似ていて使いやすい感じがします。注意点としてはGPartedであらかじめ、MBRのパーティション(/,swap./home等)を作っておき、Mintのインストーラでは、新規インストールせずに、カスタマイズのほうを選択して、マウント処理とブート領域設定していきます。途中、警告らしきメッセージも出ますが、無視して進めたところ、うまくいきました。第一世代のCPUは想定していないようですが、しばらくは、PCを無駄にせず、動画視聴等に活用できそうです。

2025年10月14日火曜日

Win11の25H2を古いPC(第3~4世代)に入れる場合の覚書

ノートA573などの第3世代でも、工夫次第でぎりぎり25H2が入るようです。一回目起動しなくなったので、なんとかならないかとChatGPTの助けを借りて、うまくいきました。

 H97M-PLUS i5-4460 も使っていますが、こちらも同様な方法でうまくいきました。

 Bios(F2キー断続押しで起動するとOk)セキュアブートをoffとするといいようです。そのためには、A573のBIOSでは一時的に管理者パスワード入れないと編集できないようでした。

〇 BIOS 設定のポイント
CSM(互換モード) Enabled 古いOS/MBRディスクとの互換性を確保
Secure Boot / OS Type Disabled または Other OS Windows 11の署名チェックを回避
Fast Boot(高速モード) Disabled 起動チェックを省略せず、SSD/USBを確実に認識
Boot Priority / Legacy First Legacy First ON 古い形式(MBR/USB/SSD)を優先して起動
⚡ Fast Bootは速度優先、Legacy Firstは互換性優先の意味

〇インストールUSB作成  Rufusなどで作成
パーティション形式:MBR(UEFI + CSM対応)
ファイルシステム:NTFS(容量大きめの場合)
「TPM・Secure Boot回避オプション」を有効にするとより安全

〇インストール後の調整(任意)
GPT形式に変換してUEFI純正起動
CSMを無効、OS Typeを「Windows UEFI mode」に戻すと、Secure Boot利用可能
古いPCでも安定してWindows 11を使える

〇注意点
第3~4世代でギリギリライン
安定して使うなら、Windows 10延命 or  Linuxを検討

※Win11が最近のPCしか対応しなくなったことが、余力ある古いPC(SSD化やメモリ増設は必要ですが)にとっては、Linux流行のきっかけになる?
※2025/10/19 実際、今回のタイミングで世界の状況はLinuxへの移行が、これまでにないほど活発になっているようです。欧州では一部組織でLinux移行を成功させているところもあるらしいです。

2025年10月5日日曜日

Haskell入門 型以外の安全性の確保 P286

 actionIO :: IO a -> IO a
actionIO action = do
  mv <- newEmptyMVar    --スレッド間通信用の空のMVarの箱をつくる
  _tid <- forkIO $ do           --スレッドをたてて
    result <- try action         --actionを実行 成功ならRight 値  例外なら Left eを返す
    putMVar mv result         --結果(Either SomeException a)をMVarに入れる
  result <- takeMVar mv    --メインスレッドでMVarから結果を受ける。入るまで待つ動作。
  case result of                       つまり、actionが終わるまで待って結果を受け取る
    Left e  -> throwIO e
    Right r -> return r

 forkIOでスレッドをわけると、普通はその中で起きた例外が親スレッドに伝わらない。
でも、この関数では、例外をつかまえ MVarを通して親スレッドに返している。

久しぶりに室内MLAアンテナでDX

 18MHzバンドで久しぶりDXが開けていた。ゼヤ(Asiatic Russia)の局長さんとFT8で交信できた。5Wの室内アンテナで届いたので、コンディションがよかったようだ。

 FT8でオンエアしている局の密度をみると、やはり、欧州、日本、北米が目立っているのがわかる。

2025年9月30日火曜日

Haskell入門 モナドによるDSLの実現 ~operational~ P274

型の変換を細かく追って、整合性を確認はしてみましたが、けっこう込み入っていて、それに気を取られると全体の構造がわかりにくいので、おおまかにとらえることも大事かと思いました。runSalesTという関数が、再帰を使って、レシピを読み取っていく構造になっているようです。

 その際、ポイントが :>>=という関数のようです。 (ひとつの命令):>>= (それに続く残りの命令) この残りの命令である右辺がkとなっていて、 これが次のrunSalesTへ再帰で渡される構造になっているようです。そして、次のrunSalesTで、また先頭の(ひとつの命令)が取り出され、それに応じて枝分かれした処理が行われ、...これを繰り返していく。

  ちょうど、リストを順に処理していく再帰と同じ構造のようです。func( [a:k])=(何らかの処理   func(k)) の形。

 簡単なoperational使ったDSLのコードをChatGPTに頼んで作ってもらいました。

sample.hs

.yamlに- operationalを追加必要し stack runghc  sample.hsで7と表示します。
あるいはstack runghc --package operational sample.hsでもいいようです。

2025年9月29日月曜日

Haskell入門 Applicativeスタイル パーサー P251

 既習のモナドを組み合わせると、パーサーもこんなふうになるというよい例だと思います。ただ、かなり複雑にはなってきていますが。 20170401のような日付のパーサーの例です。

data YMD = YMD Int Int Int deriving Show    
countRead :: Read a => Int -> Parser Char -> Parser a
countRead i = fmap read . count  i  
ymdParser :: Parser  YMD                                                                    
ymdParser = YMD <$> countRead 4 digit <*> countRead 2 digit <*> countRead 2 digit 

1. YMD は関数:データコンストラクタ YMD は、単なる値ではなく
 YMD :: Int -> Int -> Int -> YMD という「Intを3つ受け取って YMD を返す関数」でもある。
2. countRead の役割:countRead n digit は「数字を n 個読み取り、それを整数として解釈する」パーサーである。
 例えば: countRead 4 digit :: Parser Int(年を読む)
      countRead 2 digit :: Parser Int(月や日を読む)
3. <$> で最初の適用:(<$>) :: (a -> b) -> Parser a -> Parser b
 a = Int  b = Int -> Int -> YMD  関数 f = YMD 値 Parser a = countRead 4 digit
 したがって:  YMD <$> countRead 4 digit :: Parser (Int -> Int -> YMD)
 ここで、Parser の中には「年をすでに受け取った部分適用関数 YMD y」が入っている。
4. <*> で次々に引数を渡す:次の <*> により
  Parser (Int -> Int -> YMD) <*> Parser Int :: Parser (Int -> YMD)
  さらにもう一度 <*> を使うと:
  Parser (Int -> YMD) <*> Parser Int ::  Parser YMD
※イメージ表せば
 <$>:外の関数を箱に入れる    <*>:箱の中の関数に箱の中の値を渡す 

2025年9月27日土曜日

Haskell入門 Readerモナド P186 

 testrun env = ( `runReader` env)  $ do ③
  cons1 <- consume
  cons2 <- consumue
  constOthers <-  local (\e->e{powSaveMode =True}) $ do
     cons3 <- consume              ①           ②
     cons4 <- consume
     return (cons3 + cons4}
  return (cons1+cons2+consOthers)

local :: (r->r) -> Reader r a -> Reader r a    
                 ①    ②          ①がモード切替の関数 ②do以降が対象

 「最初2回通常モード後半2回がSaveモードで電力を測定したものをすべて合計」というレシピをつくり(③のdo以降)それに、testrunのenvでその都度PowerEnvを入れてやる。そんな、流れでしょうか。

 (   ) `runReader` env   は runReader   (    )   env    ということ?のようです。(   )が未適用のところでここに③のdo以下のレシピがくるような、部分適用かと。

Haskell入門 P179 Alternative型クラスでMaybeを使う

let assocs = [("hiratara",39),("shu1",0),("masaharu",32)]
do age <- lookup "honma" assocs <|> lookup "hiratara" assocs   ①
      guard $ age < 20 ②
      return age 
②が、分かりづらかった。

guard True = pure ()  つまり Just ()
guard False= empty つまり Nothing

 「do式でMaybeを使った場合、①や②のどの行であっても、Nothingが出たらそこでストップして、Nothingを返す(つまり全体の結果がNothing)。最後まで行けばJust ageですが。」 
 この「どの行であっても」がポイントになりそうです。これがあるからモナドが便利なんだろうと思いますが。この性質は、以前にも目にしていて、そのときは理解していたつもりでしたが、しばらくすると忘れてしまうようで、きちんとした言葉でメモしておくことも大事かもしれません。

2025年9月26日金曜日

Haskell 代数的データ型、レコード記法(data)とnewTypeについて

 〇 data BookInfo = Book Int String [String] deriving (Show)
型コンストラクタ名 =データコンストラクタ名 フィールドの型1 フィールドの型2,,,
(新しい型の名前=型構成子)   (値構成子)      (構成要素1,2,,,,)
データコンストラクト名を関数として扱い、Int,String,,,という型の引数に適用するとBookInfoの型の新しい値を生成できる   myInfo=Book 978~ "〇〇" ....

〇 data Bool = False | True   代数的データ型  パターンマッチで使用

〇 レコード記法:フィールドに名前
data Employee = NewEmployee { employeeAge :: Integer , employeeName::String,...}
 employee = NewEmployee { employeeName="~ ,em~   }
   employeeName employeeで名前にアクセスできる アクセサは関数

〇newType NewtypeInt  = N Int deriving (Eq,Ord,Show) N 1< N 2は Ordで可、+不可
    data DataInt = D Int  deriving (Eq,Ord,Show)と比べると制限がある
 ・ちょうど一つのフィールドのみ可   newType Okay=ExactlyOne Int
 ・パラメータは問題なし  newType Param a b = Param (Either a b)
    レコード記法も可  ただしフィールド無は不可 複数の値構成子も不可

newType NTIndexed a =NewNTIndexed { unNTIndexed :: (Integer,a)} deriving Show
 NewNTIndexedとunNTIndexedが、NtIndexed aと (Integer,a)を行き来するための関数として使えるのが便利らしい。

※なお、newtype Ph a = MkPh (Int,a)として、:t MkPhとしてみたらMkPh :: (Int, a) -> Ph aとなりました。 外側から見ると Ph aでも、中身は (Int,a)ということになります。内部構造 (Int, a) は隠して、簡潔に見せたいという考え方?

Haskell 型クラスについて

 Haskell入門とRealWorlHaskellあたりを参考に型クラスについて まとめたみた
Java         Haskell
インターフェース   型クラス     型がもつべきメソッドを規定
具象クラス      インスタンス   規定されたメソッドの実装
インスタンス     値        個々のデータ

class BasicEq  a  where    ← BasicEqという型クラスを宣言
   isEqual ::  a -> a -> Bool          インスタンスの型はaで表現 
   isEqal x y = not (isNotEqual x y)    ←このようなディフォルト実装あれば、インスタンス
   isNotEqual :: a -> a -> Bool    で繰り返しの実装を省力化できる
   isNotEqual x y= not (isEqual x y)

 この型クラスのインスタンスである型は この型クラスの中で定義されている関数を実装しているならどんな型でもいい。 この型クラスでは1つだけ関数を定義している。

  関数の型を並べるときにその名前(a)をインスタンスのクラスを表すのに使うことが必要。
:t isEqualを確認すると 
  isEqual ::  ( BasicEq a ) => a->a-> Bool  
 これは、「任意の型aに対して aがBasicEqのインスタンスである限り、isEqual は 型aのパラメータを2つ取り、Boolを返す」 

isEaqualの定義は
instance BasicEq Bool where
  isEqual True True = True
 isEqual False False =True
 isEqual _  _  =False
instance BasicEq Color where
  isEqual Red Red = True
 .....  のようにインスタンスの種類を増やせる

2025年9月22日月曜日

Haskell入門 P390

 サーバー側のビルドがうまくいかず、苦労していたけれど、deriveJSONエラーが、どうやら、上にあるものですでに処理されているものを、下の方で使うということらしい。順序を次のように変えてみたら、うまくビルドできた。最近の仕様は厳しくなっているのかもしれない。

deriveJSON defaultOptions ''Money
deriveJSON defaultOptions ''AuctionItemId
deriveJSON defaultOptions ''ItemId
deriveJSON defaultOptions ''NewItem
deriveJSON defaultOptions ''Item
deriveJSON defaultOptions ''Term
deriveJSON defaultOptions ''NewUser
deriveJSON defaultOptions ''UserId
deriveJSON defaultOptions ''Inventory
deriveJSON defaultOptions ''AuctionRequest
deriveJSON defaultOptions ''AuctionServerRequest
deriveJSON defaultOptions ''AuctionException
-- deriveJSON defaultOptions ''UUID
deriveJSON defaultOptions ''User
deriveJSON defaultOptions ''AuctionItem
deriveJSON defaultOptions ''AuctionResponse
deriveJSON defaultOptions ''AuctionServerResponse

あとは、client.hsについては、以下行の削除したら、なんとかビルドが通った。
--import qualified System.Console.Haskeline.MonadException as Haskeline (catch)

--instance Catch.MonadThrow (InputT IO) where
--    throwM e = liftIO $ throwIO e
--instance Catch.MonadCatch (InputT IO) where
--    catch act handler = Haskeline.catch act $ \e ->
--        if isSyncException e
--            then handler e
--            else throwIO e

あとは、サーバ側のMain.hsがサンプルにはなかった?ようなので追加し、.cabalもそれに合わせてmain-isを修正すると、すべてビルドを終えることができた。

※サーバへのクライアントのアクセスも、GUIでなく、すべてコマンドライン操作なので、昔のパソコン通信のようなもので、久々に懐かしい感覚を思い出しました。

2025年9月18日木曜日

クラウド経由の家計簿データ保存

  これまで、raspiにテキストデータとして、外出中の買い物データを保存して、自作家計簿ソフトでインポートするようにしていたけれど、実際、旅行中など使ってみると、削除や編集の機能もないと不便だった。そこで、sqlite3を使って、raspiのbottleはWebAPI形式にしてみた。

 スマホはjavaでCRUDができるようにしたが、これが一番時間がかかった。完全にMVCに則ってコーディングするため、メンテはしやすいだろうけど、最初はなかなか大変。画面の該当行を長押しで、編集・削除もできるようにしたところ、けっこう便利になった。一般のクラウドでとなると、維持費もまあまあかかると思うので、個人利用なら、やはり、raspiが一番の節約になりそう。

 raspiは、省エネのわりに、SSRと組み合わせてタイマー機能、タッチパッドPC起動、ネットラジオ録音とさまざま活用できて手放せない存在になっている。

2025年9月6日土曜日

gitのリモートへのクローン(備忘録)

 githubにも、方法が表示されますが、念のため手順をまとめてみました。最近は、公開鍵も使うようになっているので。

・ mkdir myproject  cd myproject      git init
・ echo "# My Project" > README.md      git add .
  git commit -m "first commit"
・リモート側で空リポジトリ作成
   (例: GitHubで myproject を新規作成)

・ ssh-keygen -t ed25519 -C "your_email@example.com"(または -t rsa でもOK)>公開鍵 (~/.ssh/id_ed25519.pub) を GitHub の[Settings] → [SSH and GPG keys] → New SSH key に登録(アカウントのほうのSettingsで)>(~/.ssh/config)につぎのようにして443ポートを使うように指定、ルータのフィルタリングを通過させたい場合必要

Host github.com
  Hostname ssh.github.com
  Port 443
  User git

・ssh -T git@github.com で接続確認

・git remote set-url origin git@github.com:ユーザー名/リポジトリ名.git

   によりパスワード不要になる。

・ローカルのブランチ名が master の場合は git branch -M main で統一

・git push -u origin main

※毎回のプッシュを簡単にするためスクリプトを作ったら、けっこう便利。
git add .
git commit -m "commit_$1"
git push -u origin main
gitPush.sh に第一引数としてコメントも入れられるよう、上記のスクリプトにした


2025年9月4日木曜日

wslでtomcat10

root権限で ネット上の情報を参考にwslでtomcat10を動かしてみた。

wget https://downloads.apache.org/tomcat/tomcat-10/v10.1.44/bin/apache-tomcat-10.1.44.tar.gz
tar -xzvf apache-tomcat-10.1.44.tar.gz
apache-tomcat-10.1.44/bin/startup.sh で起動
apache-tomcat-10.1.44/bin/shutdown.sh で停止
localhost:8080でWindowsからも見ることができた。
pico apache-tomcat-10.1.44/conf/tomcat-users.xml
 <role rolename="manager-gui"/>
  <user username="admin" password="pass" roles="manager-gui"/>

myapp/  <---プロジェクト名
 ├─ WEB-INF/
 │    ├─ classes/
 │    └─ lib/
 └─ src/
           └─ HelloServlet.java という構成にして
つぎに、jspはwebappsの下のプロジェクト名直下において、表示なるか確認
index.jsp
http://localhost:8080/myapp

そして、servletは プロジェクトのディレクトリで
javac -d WEB-INF/classes  src/HelloServlet.javaで、コンパイルすると、表示が確認できる。
ライブラリ指定必要な時は、javac -d WEB-INF/classes -cp /home/user/tomcat10/apache-tomcat-10.1.44/lib/servlet-api.jar src/HelloServlet.javaのように-cpオプションで指定

HelloWorld.java
http://localhost:8080/myapp/hello

2025年9月1日月曜日

Haskellのテストの仕様について

注意点が2つほど  このへんは、ChatGPTでもなかなか気づけなかった。まだ、試行錯誤できる人間よりは、AIは不利かもしれない。

・テストファイルひとつならSpec.hs のままでも OK
しかし、複数だと、Main.hsとしないとだめな仕様になっているようです。このへんは、気づきにくいところ。

・cabalファイルにはpackage.yamlの設定が反映されるけれど、個別のファイルの設定は反映されず、globalスコープのdependencies:のところに、依存関係を記述しないとだめだった。

dependencies:
  - base >= 4.7 && < 5
  - text
  - bytestring
  - aeson
  - sqlite-simple  などのように
  

2025年8月31日日曜日

Haskell Scottyをapache転送で外向けに

 内部LANでのサーバ稼働はうまくいったので、外向けに以前設定したraspi2のapache転送をそのまま利用することにした。ただ、これも一筋縄でいかなかった。(クッキーを利用する場合は、転送処理は難しいようなので、あくまで簡易的な利用にとどめる予定)

・sudo nano /etc/apache2/sites-available/default-ssl.confで、以下のような行を追加

ProxyPass /hs http://追加ラズパイのローカルipアドレス:3000

これで、外部からsslでhttps://ホスト.ドメイン/hsでアクセスすると追加raspi3の3000ポートに転送される。

他に苦労したところでは、

・raspi間の転送がうまくいくように、ルータのipフィルタリングの許可設定を追加

・webアプリに0,0,0,0でリスンするようにコードを書き換える必要があった。そうしないと、なぜか転送がうまくいかなかった。なお、キャッシュが残っているとうまくいかないこともあるので、ビルド、ブラウザは適宜、キャッシュクリアの操作が必要かも。あと、warpを.yamlに追加する必要があった。

  app/Main.hs


※追記:アパッチ転送で注意が必要なのは、/の転送は最後にしないとだめということ。ルートの後に、転送の設定をしてもそれは、無視されるようです。順序が大事なようです。

2025年8月30日土曜日

Haskell入門 Webアプリ(覚書)

 10章のWebアプリを読み終えたのはいいけれど、Spockは実際にビルドしても、依存関係のエラーでかなり面倒なことが判明。いろいろ、バージョンを変えて調整したが、ネット上の情報も少なく諦める。せっかくのSpockの勉強も無駄?になったようで、ちょっと回り道してしまった感じもある。

 とりあえず、Scottyあたりが、比較的メンテもされているようなので、そちらを試すことにした。まずは、簡単なコードをしばらくしまい込んでいたraspi3で、動作確認をしてみた。

・stack new sample           cd sample
・package.yamlについて:   executables>sample-exe>dependenciesに
    - sample
    - http-types
    - aeson
    - scotty
・Main.hsについて
 
・stack build       stack install
    stack exec sample-exe   でhttp://raspiのアドレス:3000/でアクセス

これで、ようやく動作の確認はできた。
    ちなみにコード修正後はstack runで  ビルドと実行ができるようだ
     stack cleanでビルド結果を削除(再ビルドしたいとき)

2025年8月25日月曜日

Haskell入門P368 ルーティング、本体

HaskellでSpockを使ったルーティングは、慣れるまで大変そうですが、無駄のない構成という感じがします。

authHook:ログイン認証
・ctx <- getContextについて:ユーザーからのリクエスト関連情報が、ある時点で箱にはいっていて、そこから、とりだしたのがctxへいく、というイメージ。
・mUser <- fmap wrsesUser readSessionについて:オブジェクトにフィールド名を関数として適用すると、該当フィールドの要素を返す仕組みになっている(P96).
readSession :: WRAction (SessionVal UserSession):現在のリクエストに紐づく セッション情報 を取得する関数 data UserSession = UserSession { wrsesUser :: Maybe User....から、取り出しmUserに

spockApp:ルーティング
・外側のprehookは認証なし、内側はauthHookで認証 うまく階層的に配置してわかりやすい構造
・get,postの別やURLと対応するActionが並べられている。
prehook (return emptyContext) $
 ├─ prehook authHook $ do
 │    ├─ get root
 │    └─ post "new_record"
 ├─ post "register"       ← authHook は適用されない
 └─ post "login"          ← authHook は適用されない

weightRecorderMiddleware:WAI ミドルウェアとして起動するための処理
runWeightRecorder cfgで定義されているように、runSpockで呼ばれる。
    ここで、spock spCfg spockApp にreturnがないが、do内のモナド計算なので不要

2025年8月24日日曜日

Haskell入門 P364 グラフ表示部の実装

ここも、分かりにくいところがあり、ChatGPTの助けを借りるが、ほぼ完ぺきにわかりやすく説明してくれるので、非常に助かる。
・weightGraphValueはMustacheへ渡すValueを返すのが役目。

・liftIO $ mapM flat wrsについて:flatでweightはそのまま使い、日付のみ"%m/%d"形式に変換し、 flat::WeightRecord-> IO (String,Double) よりmapM flat wrsはIO[(String,Double)]を返す。このへんは、mapMの働きを覚えてないと使えない、正直言って、前に学習(P174)したことを忘れており、復習して気づいた感じ。IOを含んでいるのでliftIOでWRActionモナドに持ち上げている。

・let wrss = groupBy ((==) `on` fst) . sortBy (compare `on` fst) $ flatWrsについて:
 sortBy (compare `on` fst) は、fstの日付でソートしている。groupBy ((==) `on` fst) は同じ日付のものをまとめるらしい。つまり[ [("08/20",60.5), ("08/20",61.0)],  [("08/21",60.8)]となる。wrssはリストのリストになります。(==)にそういう機能があることなど、非常に細かいところだけどChatGPTがしっかり解説してくれたのには、驚いた。
 本によれば、onは第二引数の関数を適用してから、第一引数の2項演算子を適用するという働きらしい。これと、上記の説明をみて、ようやく意味が理解できた。

・groupToValueについて:  :: [(String, Double)] -> Valueである。
   dt = head $ map fst gr→ グループの日付を取り出す(全部同じなので先頭でOK)。
   wt = avg $ map snd gr→ 複数記録がある場合は平均を取る。
 なるほど、うまくでてきています。これを使えばgroupToValue [("08/20",60.5),("08/20",61.0)]→ object ["day" ~> "08/20", "weight" ~> 60.75]となります。

2025年8月22日金曜日

Haskell入門 P354 各種操作の実装

whenはtrueならアクションを実行、startViewは実行したら次の行にはいかない。
runSqlite で (Connection -> IO m)を引数にとるため、insertUserの部分適用をうまく使っている。 (insertUser  :: IConnection c  => NewUser -> c -> IO Integerなので)
このへんがHaskellの簡潔さにつながっているのだと思う。

Haskell入門 P352 コントローラの開発

P352「type WRApp ctx= SpockCtxN ctx WRConnection WRSession WRState
type WRAciton = SpockActionCtx WRCibtext WRConnection WRSession WRState
WRAppとWRActionはWeightRecoder アプリケーションで利用するモナドです。
先ほどコンテキストにはWRContextを使うものとしてsrc/Web/Core.hsに定義しました。
 しかし、/のコンテキストは必ず()になるため、WRContextは適しません。そのため、ルーティングに用いるWRAppでは()にも対応できるよう、ctxを指定できるよう定義しています。一方で、ロジックを実際に記述するWRActionのコンテキストは、()を受け取らないようにできるため、型変数ではなくWRContext固定としています。このため、ルーティングの根本でコンテキストをWRContextに設定する必要があります。」

 この部分がよくわからなかった。どうやら、型変数ctxの例がWRContextという型などであるようだ。WRappとWRActionは厳密に関連しているのかと思ったけれど、必ずしもそういうことではなかったよう。WRAction が型変数をとらない理由は、型を固定して型安全にしたいからのよう。WRApp はルートや URL ごとに ctx が異なる可能性があるので型変数で柔軟にしている。そういうことらしい。WRappは設定データだから、いろんなデータを設定できる方がいい、でもWRActionは、安全性が求められるのである程度使える設定データは制限したい、そんな感じだろうか。

2025年8月21日木曜日

Haskell入門 P347 ユーザー登録のためのINSERT

 仕組みがわかりにくかった。

そこで、次のような質問をChatGPTにしてみた。
Q1:piNewUserは、どういうふうに使い方をするのですか?
Ans: let ins = HRR.typedInsert User.tableOfUser piNewUser がポイント
typedInsert :: Table User -> Pi User NewUser -> Insert NewUser
第1引数 User.tableOfUser → 「Userテーブルそのもの」
第2引数 piNewUser → 「NewUser から User のカラムに対応付ける射影」

let ins = HRR.typedInsert User.tableOfUser piNewUser
    u'  = u { nuPassword = dec hashed }                ins は INSERT 文のひな型

DHR.runInsert conn' ins u'     と実行すると、
u' :: NewUser の値(ユーザー名とハッシュ済パスワード)を
piNewUser に従って User テーブルの name, password カラムに対応付け
実際に DB へ INSERT

Q2: 要するに、手順を最初にくみたてて、最後に、runInsertで実行するのですね。
Ans:  はい、その理解でバッチリです!
  まとめると:
   piNewUser で「どう射影するか」を定義(テーブルと型の橋渡し)。
   typedInsert で「INSERT文のひな型」を作成。
   runInsert で「実際の値」を流し込んでDBに送信。

※ Haskellは、手続き型のように「値を受け取りながら逐次SQL発行」というやり方はあまりせず、まず「設計図を型安全に作る値を流し込む」という 宣言的な流れ
 型安全性が高い:SQL文やカラム名の間違いをコンパイル時に検出できる
 SQLインジェクション対策が組み込みである:値を直接文字列連結しないので安全
 トランザクション管理が明確:withTransaction の中で設計図に値を流し込むので、途中でエラーがあればロールバック可能
 コードの再利用性が高い:射影(piNewUser のような定義)を作っておくと、INSERTや  SELECTで同じマッピングを使い回せる
 などの利点があるらしい
Q3:makeRecordPersistableDefault ''NewUser はどういう意味?
Ans:NewUser を Relational-Record の「DBに入出力できる型」として登録する宣言、Template Haskell によって必要な型クラスインスタンスを自動生成している
「この型をSQLに流せるようにしますよ!」と最初に宣言しておく儀式 みたいなもの
Q4:Template Haskellとは?(P340にも説明はありますが)
Ans:「Haskellプログラム自身を生成する Haskellプログラム」を書ける
Q5:自動生成ですね。DjangoやRuby on Railsなどでも、DB初期化で似たような処理あったような気がしますね.
Ans:まさに DjangoRuby on Rails と同じ発想です。
Rails/Django = 実行時に自動生成・マッピング
Haskell(TH) = コンパイル時に自動生成・型安全にマッピング
Q6:user <- DHR.runQuery conn q name >>= DHR.listToUniqueのDHR.listToUniqueの働きは?
Ans:[] の場合 → Nothing を返す、[x] の場合 → Just x を返す、[x, y, ...] の場合 → エラーか Nothing を返す。「DB側にユニーク制約があるとは限らない」設計を想定。
Q7:checkHash user | validated = Just user | otherwise = Nothingの意味は?
Ans: if ... else if ... else if ... elseのイメージで、最初にtrueになったところが checkHash userの値。ガードの機能(p62で既習)

2025年8月18日月曜日

Haskell入門 P326 処理のまとめ

stack install で実行ファイルを作り、動作確認してみた。これも、一筋縄ではいかず、Windowsだと、文字エンコードなど配慮しないとうまくいかなかった。エラーメッセージ見たり、ChatGPTに聞いたりしながら、なんとか解決。
 
echo [{"age":"aa","name":"名前","telnumber":"abcdef"},"age":"bb","name":"abcd","telnumber":"jkl"}] > test.json
としてファイルをつくってから
hjq-exe "{\"name\":.[1].name,\"telnumber\":.[1].telnumber}" test.json
としたらうまくいった。ハイフンがあるとうまくいかず、カットする必要あった。なかなか、大変だった。


Hjq.hs
・note:MaybeをEitherに変換    decode:ByteStringをValueに変換
 first:Rightはそのまま、Leftに関数を適用


Haskell入門 P323 テストようやく終了

 本のままでは、動かず新しいバージョンに合わせた修正が必要だった。

よくわからないところを確認してみた。
Spec.hs
・applyFilterTestについて
   ^?  指定データを1部取り出したいとき使用(lens)
 nth 2 リストの3番目要素取り出し
   fmap Right (testData^?key "string-field") だと  fmap::(a->b)->f a->f bでみると
 (a->b)がRight  f aがMaybe Value   f bがJustつまりMaybe(Either e Value)
 これにRightが適用なるようだ

Parser.hs
・queryArrayの jqQueryParser `sepBy` schar ',' について
  sepByは中値だが、2引数関数で schar ','を区切りとして jqQueryParserでパース

Query.hs
・applyFilter (JqField fieldName n) obj@(Object _)
  = join $ noteNotFoundError (T.pack fieldName) (fmap (applyFilter n) (obj ^? key (fromText(T.pack fieldName))))  について
   obj@(Object _)はObjectとか確認し、その値をobjとして利用可能
 joinはMaybeをはずすため

・executeQuery (JqQueryObject o) v
   = fmap (Object . KM.fromList . fmap (\(k,v) -> (Key.fromText k, v)))
    . sequence ②
    . fmap sequence ①
    $ fmap (fmap $ flip executeQuery v) o  について        
    左辺の(JqQueryObject o) vは{"name":.name,"age":.age}::[(Text,JqQuery)]
    右辺の fmap $ flip executeQuery v のflipは引数を逆順にして、部分適用を意図した 通りにするために使う。(flip executeQuery v) q == executeQuery q v 
  fmap (fmap $ flip executeQuery v) は、内側のfmapで( , )への処理を、外側のfmapで上の関数使って[  , , ]への処理を行う。
  sequenceは①で Eitherを外に出していく [(either Text (Text,Value))]
        ②で Ehter Text [(Text,Value)]にする

   パーシングは、なかなか複雑

2025年8月16日土曜日

Haskell入門 P318

 スペースがある場合のパース

Spec.hs

Parser.hs
本ではscharが標準である?のかもしれないが、新しいライブラリにはないようで、作る必要があった。ChatGPTから作ってもらう。ついでに、以下のような説明もしてもらうが、 Megaparsec自体なじみがないので、難しい感じが。理解できるようになるためには、もう少し時間がかかりそう。
1. sc :: Parser ()
sc = L.space space1 empty empty
目的:空白やコメントをまとめてスキップする
L.space は Megaparsec が提供する空白スキップ用パーサ。
引数:
space1 → 1個以上の空白文字(' ', '\t', '\n')をスキップ
empty → 行コメントの始まり(今回は使わないので空)
empty → ブロックコメントの始まり(今回は使わないので空)
つまり、この sc は「空白があるところを自由に無視する」パーサです。

2. lexeme :: Parser a -> Parser a
lexeme = L.lexeme sc
目的:トークンを読んだあと、自動で空白をスキップする
使い方:
lexeme L.decimal    -- 数字を読み取ったあと、空白を消費
lexeme (some letterChar)  -- 識別子を読み取ったあと、空白を消費
イメージ:
入力: "123   "
lexeme L.decimal → 123 を返す、空白も消費ない場合は、後ろの空白が残り、パースが失敗しやすくなります。


3. symbol :: String -> Parser String
symbol = L.symbol sc
目的:記号(キーワードや演算子)を読んだあと空白をスキップ
例:
symbol "."  -- ドットを読み取り、空白も消費     symbol "["  -- 左ブラケットを読み取り、空白も消費      内部的には lexeme (string s) と同じような働きです。


4. schar :: Char -> Parser Char
schar c = lexeme (char c)
目的:単一文字のトークンを読み取り、空白をスキップ
文字 . や [ ] の後ろに空白があっても問題なくパースできる
例:
schar '.'  -- "." と後ろの空白をまとめて消費      schar '['  -- "[" と後ろの空白をまとめて消費

他にParser.hsで追加で確認したいところ:
・type Parser = Parsec Void String:  Void エラーの型(ない)  String 入力の型
  Parsecのほうがカスタマイズしやすい Parser a=Parsec Void String a     a:結果
・filterRest = try parseIndex <|> try parseField <|> pure JqNil
      try:失敗して消費しないなら <|>の右へ  失敗して消費したら<|>の右は試さない
      消費の意味:対象テキスト ab でパーサーacなら消費する、対象テキストcdでパーサー  
        efなら消費してない
・  name <- lexeme (some letterChar) 
   someは1回以上繰り返し  letterChar: a~zA~Zのパース
・  rest <- option JqNil (schar '.' *> filterRest <|> parseField)
    option::   a      ->        Paser a       ->        Paser a
             ディフォルト値  試すパーサ   失敗したらaのディフォルト値返す


Haskell入門 P316 修正コード

 P316のコードが動作しなかったので、ChatGPTから同等のものに書き直してもらったのがこちら。新しいライブラリMegaparsecを使うといいらしい。

Parser.hs

・type Parser =Parsec Void String     :Voidがエラーの型(ない) Stringが入力の型
   Parser   a     =   Parsec Void String  a
 限られた使い方 aが結果     Parsecのほうがカスタマイズしやすいといえる
・try paraseIndex <|>   try parseField  <|> pure JqNil    で<|>は左が失敗したら右ためす
   tryは 失敗しても入力を消費せず次を代わりにためす (入力を巻き戻す)
・some letterChar     :  some 1回以上繰り返し  letterChar a~zA~Zのパース
・option JqNil  (char '.' *> filterRest <|>  parseField)
      option::  a -> Parser a -> Parser a    
         ディフォルト値->試すパーサ->失敗したら ディフォルトaを返す
      char '.' *> filterRest    :  .を消費し、filterRest返す
       ここではtry不要。すでにfilterRestの中でtryは終えているので

Haskell入門 P316

 このへんのパーサ扱ったところはかなりややこしくなっている。
結局、コードが古くてうまく動作せず、別のライブラリを使うことになった。

でも、いちおう、古いほうも、コードをいろいろ確認してみた。
・showParserResult $ parse (jqFilterParser <* endOfInput) s `feed` ""は
showParserResult $ (parse (jqFilterParser <* endOfInput) s) `feed` ""と同じ意味
<* endOfInput 該当しないところはパースせず `feed` ""はパース停止の決まり文句のようなものらしい

・fmap pack $ many1 (letter <|> char '-' <|>..... digit())について
many1 は  letter <|> char '-' <|> ... <|> digit は 1文字分のパーサー
many1 (...) はこれを 1回以上繰り返して成功した結果をリスト [Char] にまとめる
fmap pack によって [Char]Text に変換  
        letter :: Parser Char なので   many1 letter :: Parser [Char] になります。
箱(Parser)はそのままで 中身 [Char] が Text に変わる

・JqIndex <$> パース1 <*> バース2 の意味について復習
<$>で最初に部分適用の関数ができて、その関数のまだ未適用な部分に<*>を順次適用していくしくみ
 パーサの場合、関数がつぎつぎと、無限に適用できる引数があるようなもの。その場合は、つねに、部分適用な関数のままでJqIndexが残ることになるといえそう。再帰状態になるのかも。

2025年8月13日水曜日

Haskell入門 P315 パーサの作成

 本のコードのままではだめで、けっこう厳密さが要求された。バージョンの違いか?

・型のスコープとインポートは明示的に
・Text と String は別物    (T.pack ".")で Textに
・コンストラクタもエクスポートリストで見えるようにする     (..)など利用
・stack.yaml / package.yaml の依存関係はビルド対象ごとに確認(ライブラリも指定)
といった注意も必要なことがわかる。

ちなみに修正したものは
Spec.hs

Parser.hs

Hjq.hs

package.yaml

Haskell入門 P314 HUnitによる自動テスト

 テストファーストの考え方をとっているようで、最初にテストの方法がでていた。
ただ、本の内容はバージョンが古くそのままでは動かなかった。
・Test suite not yet implementedとでるので
  package.yamlにtest:hjq-test:dependencies:のところに - HUnitを追加
  Spec.hs の先頭にimport Test.HUnit 追加
・文字エンコードでエラーがでるので
  Dosプロンプトのショートカットに cmd /k "chcp 65001 &&  cd パス"のように、事前にエンコード切り替えをいれる
・runTestTTの型が新しいバージョンでは 返り値が IO Countsというものらしいので
 以下のようなコードにするらしい。

import Test.HUnit
import System.Exit (exitFailure, exitSuccess)
main :: IO ()
main = do
    counts <- runTestTT $ "Test1" ~: 1 + 1 ~?= 2
    if errors counts + failures counts == 0
        then exitSuccess
        else exitFailure

これで、ようやく、うまく動作した。

2025年8月10日日曜日

Haskell入門P286

以下のコードの目的は、子スレッドのエラーがメインスレッドに影響しないようにしたいため、隔離しているようです。
actionIO ::  IO a -> IO a
actionIO  action = do
 mv <- newEmptyMVar :: IO (MVar (Either SomeException a))
 _tid <- forkIO $ do
  result <- try acttion
  putMVar mv result
 result <- takeMVar mv
 case result of
  Left e -> throwIO e
  Right r -> return 

1. actionIO :: IO a -> IO a
IO aのアクションを引数にとり、結果もIO aとして返す関数です。引数のactionを別スレッドで実行し、その結果を取得します。

2. mv <- newEmptyMVar :: IO (MVar (Either SomeException a))
新しい空のMVarを作成します。MVarはスレッド間で値のやり取りができる同期変数です。
型は MVar (Either SomeException a) としています。Either SomeException aは、「例外が起きたか」あるいは「正常に値が得られたか」を表すために使います。

3. _tid <- forkIO $ do ...
forkIOで新しい軽量スレッドを作り、その中でactionを実行します。
forkIOはスレッドIDを返しますが、このコードでは使わないので_tidとして無視しています。

4. result <- try action
tryは、例外が発生する可能性があるIOアクションを安全に実行し、成功時はRight a 例外発生時はLeft SomeExceptionの形で結果を返します。

5. putMVar mv result
mv(空のMVar)に結果を格納します。これでメインスレッドはこの結果を待つことができます。

6. result <- takeMVar mv
メインスレッドで、mvに格納されるまで待ちます。forkIOの中の処理が終わりputMVarが呼ばれるまでブロックされます。

2025年8月9日土曜日

Haskell入門 P285 MVarによるスレッド間の通信

 ChatGPTもlevel5になって、さらにバージョンアップした感じです。

本を読んでも、なかなか理解しにくかったところも、ChatGPTにコードを解説してもらうとすぐに理解できたので、質問者のレベルに合わせて説明できる能力に驚いています。


・m <- newEmptyMVar newEmptyMVarで空のMVarを作成  これはスレッド間の通知用の「信号」として使う予定
 ・forkIOで新しい軽量スレッドを作成。
  この新しいスレッドの中で、myThreadIdでスレッドIDを取得し、コンソールに表示。
  ・putMVar m ()で空のMVarに通知(単なる空のタプル () を入れているだけ)を送る。
  ・メインスレッドはtakeMVar mで、MVarに値が入るのを待つ(ブロックされる)。
  子スレッドが2秒後にputMVarで通知すると、この待機が解除される。       
  ・メインスレッドは、子スレッドが終わったことをMVar経由で待機している。
   子スレッドは、重たい処理の後にMVarに通知し、メインスレッドに処理完了を知らせる。

 ※ putMVar m () は、普通は MVar aにaを入れる(例えばMVar IntにIntを入れるように)。今は()を入れているが、これはCでいえばVoid scalaでいえば、Unitみたいなもの。

2025年7月2日水曜日

今年から市民農園再開

 しばらくやめていた市民農園に再挑戦で、今年は小玉スイカの空中栽培も試してみた。植え付け時は、炭疽病を心配し、乗り越えたかと思えば、今度はウリハムシ、そして受粉がなかなかうまくいかないとか、いろいろありましたが、今のところ、それほど雨に悩まされることなく病気の症状もおさまっているようです。このまま梅雨明けしてくれるといいのですが。

 
 虫や病気の心配も少なくネットもいらず、片付けも楽、意外と手間がかからず、コンスタントに収穫できるのがつるなしインゲンです。
 

 ※小玉スイカは、受粉日のタグをつけて35~40日後に収穫したところ、ちょうどよい甘さになりました。2025/7/25

2025年6月26日木曜日

ロープの結び方

 畑作業でもよく使うので、男結び等について 図にまとめてみました。(トラックロープの結び方は南京結びともいうようです。) 他にも、巻き結び、もやい結び、結束結び、自在結び、ひとえつぎ結び等、覚えておくと便利なようです。

GASではJSON.stringfyをつかったほうがいいようです

 畑の収穫記録をGASで管理(収穫の個数を記録しその都度、合計の確認)しようかと、ChatGPTにコード頼んでみたけど、なかなか一筋縄ではいかない。AIにより、だいぶコーディングは楽になっているが、やはり、ある程度やりとりしながら、人間側が修正してあげないと動かなかった。

 最初、ChatGPTはサーバ(GAS)からのレスポンスデータを単純にオブジェクトで渡すコードを提示してくれたけれど、それではうまくいかず、やはり、JSON.stringfyを使わないとだめだった。

※ MEMO欄を追加しました。2025/6/27

2025年6月2日月曜日

ガロア理論入門(アルティン) 問11-3(2)

P117 p素数 Φp^n(x)=Φp(x^(p^(n-1)))が既約であることを示す問題の途中の変形がしばらくわからず悩む。

Φp(x^(p-1)+(pでわりきれる項)+1)={x^(p^(n-1))+(pでわりきれる項)}^(p-1)+(pで割り切れる項)+pとなる理由

∵前問で①Φp(x+1)=((x+1)^p-1)/((x+1)-1)=x^(p-1)+Σk=1~(p-2) pCk x^(p-k-1)+p が言えていたので、これを使うとよいことにきづく。今の場合、X=x^(p-1)+(pでわりきれる項) としてこれを①のxをXで置き換えるとうまくいくようです。

 前問をつかっているということに、きづかなかったためしばらく悩みました。よく読むと問題にも(1)と同様にして解く と書いてあるのを見逃していました。

2025年5月17日土曜日

アルティンのガロア理論入門 P106

 途中の式変形で、すこし手こずる。x^(q^n)-α^(q^n)-(x-α)を(x-α)で割ってから、x=αを代入した式がq^n*α^(q^n-1)-1となることを示したい。ChatGPTにすぐ頼ってしまったが、いまいちすっきりしない。

 与式をf(x)とすると  f(x)=(x-α)h(x)とみなし h(x)=f(x)/(x-α)だから、h(x)=f'(x)とみなせるからという説明だった。たしかに、x→αでは、解析的には微分だが、、、、(自分には高度すぎる?)。

 と、少し間をおいてあらためて考えると 単純に式の割り算をすると、

Σ i=0~q^(n-1)     α^i*x^(q^n-i-1)  -1  となることに気づく。これにx=αを入れると、結論が言えるようだ。自分としては、こちらのほうが納得できる。

2025年3月29日土曜日

モナドの活用

 Haskell入門 を久しぶりに読み直してみた。P168にMaybeモナドについて少し復習してみた。

getItemWithMonad menu category name =do
  subMenu <- lookup category menu
  price <- lookup name subMenu
  return (category,name,price)

途中、Nothingを記述しなくても自動的に、該当しなければ、最後はNothingになる。うまくできていると思う。
これを、手続き型言語で、実現しようとすると条件分岐に頼らざるを得ないけど、その必要もない。
このへんが、関数型言語のモナドの強みなのかもしれない。

追記>試しに、ChatGPTで、ELMのMaybeを使うコードに変換してみた。ELMはモナドをサポートしていないため、少しコード量が増えてしまうようだ。
type alias Menu = Dict String (Dict String Float)
getItemWithMonad : Menu -> String -> String -> Result String (String, String, Float)
getItemWithMonad menu category name =
    case Dict.get category menu of
        Just subMenu ->
            case Dict.get name subMenu of
                Just price -> 
                    Ok (category, name, price)
                Nothing -> 
                    Err "Item not found"
        Nothing -> 
            Err "Category not found"

2025年3月19日水曜日

1960年代からの国債残高の増加率をグラフにしてみた。

 

 国債の増え方が話題になっているようなので、実際のところどうなのか、公式データを加工して処理してみました。この計算の仕方が、実際の増え方を表しているかどうか議論のあるところかもしれませんが、ある程度の参考にはなりそうです。
 縦軸は前年比の増加率(%)です。ちなみに、1873年 0.234億円 2024年 11053645億円ということのようなので この期間の1年あたりの平均増加率を計算すると (11053645/0.234)^(1/(2024-1873))=1.124   ということで、ほぼ12%程度です。
 1985年あたりから10%切るようになっていますね。それ以来ほとんど、(1998年以外は)平均に届いてないようです。

追加:ちなみに、近年のものですがアメリカも調べてみました。日本のように、5%切ることは少ないような感じです。