関数型パーサー
Table of Contents
行列において
田舎でも行列が有るんです。
で、オイラーの前に並んでいたオバチャンが、やけに格好いい腕時計をしてい た。失礼ながらオバチャンには、不釣り合いだぞ。超若者っぽい。
さりげなく、聞いてみた。だって、暇なんだもん。そしたら、オバチャン曰く、 時計に血圧・脈拍計、酸素濃度計が組込まれたもの。スマホと連動するそうだ。
散歩とか運動時に、体に無理がかかっていないか確認するのに使っているとか。 時刻もタッチするだけで、分かるんで、便利ですよーとの事。
随分高かったんでしょと水を向けてみると、そんなにしないですよ。楽天とか で、1万円以下で、よりどりみどりですってさ。
腕時計 血圧 酸素濃度 スマホ連動 本当だ。世の中舐めてました。進んでるね。時計なんて言い方は昭和世代か。 スマートウォッチって言わないといけないんだな。
歳を聞かれたので71って言ったら、同級生ですねって返された。そこから話し がはずんで、あっと言う間に時間が過ぎた。別れ際、楽しかったですって、お 礼を言われた。こちらこそです。スマホとにらめっこって、孤独な 時間の過し方。みんなでワイワイやればいいのに。何時から、引きこもりに なっちゃたんだよう。
で、オバチャン情報で、ネバネバ野菜である、モロヘイヤをGet。地場のオクラは、 まだ出ていなかった。そうよね、ネバネバ系は体にいいぞ。次回はあるかな?
stack update
どうも勝手にアップグレードされた節がある。こんなに太った。
[sakae@arch ~]$ du -sh .stack 6.8G .stack
どこが肥大化してる?
[sakae@arch .stack]$ du -sh * 4.0K config.yaml 332K global-project 1.7G pantry 4.9G programs :
なんと、古いのも残ってる。
/home/sakae/.stack/programs/x86_64-linux [sakae@arch x86_64-linux]$ ls ghc-tinfo6-9.2.8/ ghc-tinfo6-9.2.8.tar.xz ghc-tinfo6-9.4.5.installed ghc-tinfo6-9.2.8.installed ghc-tinfo6-9.4.5/ ghc-tinfo6-9.4.5.tar.xz
実際にプロダクトを作ると、.stack-work/ に、もろもろもデータ類が作成さ れる。ちっちゃなプログラムでも、20Mぐらいは占めていたぞ。サイズに頓着 しない富豪的なやつです。
piki
昔お世話になったpikiは、パーサーを使っていたな。どんな風にしてたか調べ てみる。
piki: Yet another text-to-html converter
doHtml :: [FilePath] -> IO () doHtml [template,input] = toHTML <$> L.readFile template <*> L.readFile input >>= L.putStr doHtml [template] = toHTML <$> L.readFile template <*> L.getContents >>= L.putStr doHtml _ = printUsage
これが入口。
toHTML :: L.Text -> L.Text -> L.Text toHTML tmp inp = build $ replace tmp [("body",body),("title",fromXText title)] where elems = piki inp body = mcatmap toHtml elems title = getTitle elems
テンプレートファイル中の目印($title, $body)を変換するんだな。変換とい うより、includeかな、その時にマクロっぽい変換が発生する。
piki :: L.Text -> [Element] piki line = either reportError id res where res = parse document "" $ L.lines line document :: LineParser [Element] document = clean *> many element <* eof element :: LineParser Element element = choice $ map lexeme [ division , headline , hrule , uolist , dlist , image , table , preformatted , paragraph ]
やっと個別のパーサに分解されてきた。沢山あるので代表例で、headlineは、 <h1>xxx</h1>みたいなタグを扱う。
headline :: LineParser Element headline = do (lvl,txt) <- levelTitle <$> firstCharIs pikiTitle ttl <- getText txt return $ H lvl ttl where levelTitle line = (lvl,txt) where (mark, txt) = L.span (== pikiTitle) line lvl = fromIntegral $ L.length mark
これは、各種piki記法の定義だ。
data Element = HR | H Int XText :
最終的に、こんな風にして、htmlになる。
instance ToHtml Element where toHtml HR = solo ("hr",[]) toHtml (H n str) = fromXText str // ("h" +++ toB (L.pack (show lvl))) where lvl = min 6 n :
ask Chat.GPT
golangと比べた時のhaskellの優位性を5個、挙げてください
HaskellはGolangと比較していくつかの優れた特徴を持っています。以下に、HaskellのGolangに対する優位性のいくつかを挙げます。
- 静的型付けと型推論: Haskellは強力な型システムを持ち、静的型付けによるタイプエラーの検出をサポートします。さらに、Haskellの型推論機能により、多くの場合、型アノテーションを明示的に書く必要がありません。これにより、より安全なプログラムを書くことができます。
- 純粋関数型プログラミング: Haskellは純粋関数型プログラミング言語であり、副作用のない関数を作成することができます。これにより、コードのテスト、デバッグ、並行実行が容易になります。また、関数型プログラミングの特性により、コードの抽象化と再利用性が向上します。
- 強力なパターンマッチング: Haskellは強力なパターンマッチング機能を備えています。パターンマッチングを使用することで、データ構造のさまざまなパターンに基づいて処理を行うことができます。これにより、コードの読みやすさと保守性が向上します。
- ラムダ式と高階関数: Haskellはラムダ式(無名関数)と高階関数をサポートしています。これにより、関数を値として扱うことができ、関数の組み合わせや変換が容易になります。高階関数を使用することで、コードの柔軟性と拡張性が向上します。
- モナドと型クラス: Haskellはモナドと呼ばれる概念を利用して副作用を制御し、純粋な環境でプログラムを記述することができます。また、型クラスシステムを使用して、異なる型に対して共通のインターフェースを提供することができます。これにより、再利用可能なコードの作成と拡張が容易になります。
これらはHaskellの主な特徴の一部ですが、他にもさまざまな優位性があります。それぞれのプログラミング言語には異なる特性と用途がありますので、具体的な要件やプロジェクトの目標に基づいて適切な言語を選択することが重要です。
逆にgolangの優位点は何ですか
Golang(Go言語)の優位点には以下のようなものがあります。
- 簡潔で直感的な文法: Golangはシンプルで読みやすい文法を持っています。C言語のような慣れ親しんだ構文を基にしており、学習コストが比較的低いです。また、文法が簡潔なため、コードの書きやすさと理解しやすさが向上します。
- エフィシェントな並行処理: Golangはゴルーチン(Goroutine)とチャネル(Channel)という機能を提供しており、並行処理を簡単かつ効率的に行うことができます。ゴルーチンは軽量なスレッドのようなものであり、非同期な処理を効果的にサポートします。また、チャネルを使用することで、ゴルーチン間のデータ共有と同期が容易になります。
- 高速な実行性能: Golangはコンパイル言語であり、静的バイナリを生成します。そのため、高速な実行性能を発揮します。また、ガベージコレクタ(Garbage Collector)によるメモリ管理も組み込まれており、開発者が手動でメモリ管理を行う必要がありません。
- 豊富な標準ライブラリ: Golangには豊富な標準ライブラリがあります。ネットワーキング、暗号化、データベース、Web開発など、さまざまな用途に使用できる便利な機能が提供されています。これにより、開発者は自分で車輪を再発明する必要がなくなり、生産性が向上します。
- クロスプラットフォーム対応: Golangはクロスプラットフォームな開発に適しています。コンパイルされたバイナリはターゲットのオペレーティングシステムとアーキテクチャに依存せず、異なる環境で実行できます。これにより、アプリケーションのデプロイと配布が容易になります。
これらはGolangの主な優位点の一部です。Golangはシステムプログラミングやネットワークプログラミング、並行処理などの用途に特に優れています。しかし、言語選択はプロジェクトの目標と要件に基づいて行う必要があります。
色々聞いてみると、2021年9月までのネット情報も元に回答してるとか。コー ドを提示して添削してもらうとか、仕様を与えてコードを生成もできるよと、 自慢してた。
今度やってみよっと。孫さんも大好きで使っているみたいだからね。たとえ嘘 八百でも、アイデアを汲むのには、うってつけ。Bugが取れない時は、ティディ ベアに話かけると良いとも言うからね。それから、 ChatGPTと井戸端会議をする~「あの名作映画」について雑談したら、感激の 体験だった こういう体験をした人も居る。
google bard
日本も遅ればせながら、生成AIに乗り出すみたい。グルルさんはどうしてる?
ググルに嫌味な質問
golangと比べた時のhaskellの優位性を5個、挙げてください
はい、GoとHaskellを比較したとき、Haskellの優位性は次の5つです。
- 純粋な関数型言語であるため、副作用がなく、デバッグが容易である。
- 型推論がサポートされているため、型を書く手間が省ける。
- 高階関数やモナドなどの高度な抽象化がサポートされているため、複雑なプログラムを簡単に記述できる。
- 並列処理が容易であるため、パフォーマンスが優れている。
- 静的型付け言語であるため、実行時のエラーを防ぐことができる。
Haskellは、純粋な関数型言語であり、型推論、高階関数、モナドなどの高度な抽象化をサポートしているため、複雑なプログラムを簡単に記述し、並列処理が容易で、パフォーマンスが優れている。また、静的型付け言語であるため、実行時のエラーを防ぐことができる。
Goは、静的型付け言語であり、並列処理が容易で、パフォーマンスが優れている。また、Goは、Web開発、システムプログラミング、ネットワークプログラミングなどに適している。
HaskellとGoは、どちらも優れたプログラミング言語であるが、それぞれの強 みと弱みがある。Haskellは、並列処理や複雑なプログラムの記述に優れてい るが、Goは、Web開発やシステムプログラミングに優れている。
聞いてもいない事を宣伝してんな。まあ、そんな物だろう。 結果をクリックボードで取り出せるかと思ったら、gmailへの下書きになるの ね。ちょっと残念。
parsec
前回の最後で、tryの正体に迫った時、問題は更に奥にあると看破した。識者 の見解を聞いてみた。
Parsec コンビネータ getInput, getPosition
自分で、コードを掘り出してみる。 Char.hs
hexDigit :: (Stream s m Char) => ParsecT s u m Char hexDigit = satisfy isHexDigit <?> "hexadecimal digit" anyChar :: (Stream s m Char) => ParsecT s u m Char anyChar = satisfy (const True)
みんなまとめて、satisfyが面倒を見ているんだな。
satisfy :: (Stream s m Char) => (Char -> Bool) -> ParsecT s u m Char satisfy f = tokenPrim (\c -> show [c]) (\pos c _cs -> updatePosChar pos c) (\c -> if f c then Just c else Nothing)
関数を3個用意して、tokenPrimに移譲。依頼された関数fが満足すれば丁度OK ね。不満足なら答無し。それをもう少しエラーっぽい説明文に、どこかで変換 するんだな。それと共に、注目文字位置が更新される。
どう逆さになっても、hexDigitを呼出て、無傷に澄む訳にはいかないな。この 枠組みを壊さない限りは。
もう、これぐらにする。
mini parsec
うんと優しい物はないかと探してみたら、 モナディック・パーサー こういうのが出てきた。
これって、プログラミングHaskell本(関数型パーサー)の、訳者自身による解説編 だ。この本を持っていなくとも、大いに参考になるぞ。
新ためて本を見直ししたら、訳者のサインがなされていた。2009.11.20 どん なシチエーションでサインを頂いたか、まっ たく記憶にございません。で、日付を頼りに検索。 Haskellナイト
動かそうとしたら、import Monad の所で、そんなの無いといわれた。何時の 時代か分からないけど、現代には通じない環境になってるのね。先輩格の parsecを参考にMonadと称するモジュールを全部入りにしてみた。 そしたら、こんなエラーが出現。
app/Main.hs:21:10: error: • No instance for (Applicative Parser) arising from the superclasses of an instance declaration • In the instance declaration for ‘Monad Parser’ | 21 | instance Monad Parser where
翻訳させてみると、インスタンス宣言のスーパークラスから生じる (Applicative Parser) のインスタンスがありません 、って事みたいだ。 他に、前提条件が必要なのか。
参考までに、 hugs98 Prelude.hsにあるMonadをあげておく。単純で分かり易い。
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b fail :: String -> m a -- Minimal complete definition: (>>=), return p >> q = p >>= \ _ -> q fail s = error s sequence :: Monad m => [m a] -> m [a] sequence [] = return [] sequence (c:cs) = do x <- c xs <- sequence cs return (x:xs) :
Haskellで以下のエラーが出てしまう (Applicative Parser)
7.10 change よい事なら、躊躇わず実施。どこかの国とは大違い! たとえ、リ グリッションテストがパスしなくとも、正しい道を歩むのが象牙の塔の役割で す。それに振り回される周りは大迷惑ってか。
Functor-Applicative-Monad Proposal
Haskell: Monadクラスのこれまでとこれから いろいろあるのね。
other parsec
Haskell 型クラス覚書(Functor、Applicative、Monad、Semigroup、Monoid、 MonadPlus、Alternative)
箱で考えるFunctor、ApplicativeそしてMonad
Haskellで重要な型を使って、パーサーを提示してしまうって、今のオイラー の時流にのってて、ピッタリな題材だ。何度も咀嚼してみよう。
newtype Parser a = Parser { parse :: Main.ReadS a } type ReadS a = String -> [(a, String)] item :: Parser Char item = Parser $ \s -> case s of [] -> [] (c:cs) -> [(c, cs)] failure :: Parser a failure = Parser $ const []
これだけで、下記の事が出来てしまう。
λ> parse item "xyz" [('x',"yz")] λ> parse item "x" [('x',"")] λ> parse item "" []
これ、すごいH本の総集編だな。実に役立つわい。
haskell books
etc
Weeder 草刈機 到達不能なコードの指摘装置 git checkout 2.4.0 (for GHC 9.2.8)
[19 of 84] Compiling Basement.Numerical.Conversion ( Basement/Numerical/Conversion.hs, dist/build/Basement/Numerical/Conversion.o, dist/build/Basement/Numerical/Conversion.dyn_o ) Basement/Numerical/Conversion.hs:29:1: error: Could not find module ‘GHC.IntWord64’ Use -v (or `:set -v` in ghci) to see a list of the files searched for. | 29 | import GHC.IntWord64 | ^^^^^^^^^^^^^^^^^^^^ cabal: Failed to build basement-0.0.16 (which is required by exe:weeder from weeder-2.4.0).
32Bitの環境では、動かない罠?
{-# LANGUAGE CPP #-} #if WORD_SIZE_IN_BITS < 64 import GHC.IntWord64 #endif
こんな風に定義すればいいのかな?
import Data.Word (Word64) myNumber :: Word64 myNumber = 42
やってみたら、別の所が出血した。もう32bit環境は顕らめるしか。