2025年8月16日土曜日

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