Open2

『Haskellによるプログラミングの思考法』のメモ

nabeyangnabeyang

pdf版が出てるのを知ったので、買ってしまった。
https://tatsu-zine.com/books/thinking-functionally-with-haskell

オーム社から出ている『関数プログラミング入門』を書き直したもののようだ。
https://shop.ohmsha.co.jp/shopdetail/000000001936/
環境は、こちらを参考に入れる。なぜかVSCodeのMain.hsの1行目が赤で表示されるが、とりあえず動くのでそのまま。
https://blog.penginmura.tech/entry/2021/02/26/150221

実行方法のメモ。プロジェクトのルートで以下のコマンドを実行。

$ stack build
$ stack run

または

$ stack ghci
> main
nabeyangnabeyang

例題: 頻出単語

以前、Haskellを本で勉強したときはファイルから読んだり、書き込んだりして、直接Haskell使って何かしたということがなかった反省があるので、ただ写経するのではなく、実際に文章の頻出単語を計算してみる。

module CommonWords where
import Data.Char (toLower, GeneralCategory (LowercaseLetter))
import Data.List (sort, sortBy)
import Data.Ord (comparing)
import Text.Printf (printf)
import System.IO (IOMode(ReadMode), hGetContents, openFile, hClose)

sortWords :: [String] -> [String]
sortWords = sort

countRuns :: [String] -> [(Int, String)]
countRuns [] = []
countRuns (x:xs) = (length q + 1, x) : countRuns p
                   where 
                       q = [a | a <- xs, a == x]
                       p = [a | a <- xs, a /= x]

sortRuns :: [(Int, String)] -> [(Int, String)]
sortRuns = (sortBy . flip) (comparing fst)

showRun :: (Int, String) -> String 
showRun (i, x) = printf "%s %d\n" x i

commonWords :: Int -> String -> String
commonWords n = concat . map showRun .take n . sortRuns . countRuns . sortWords . words . map toLower

printCommonWords :: Int -> FilePath -> IO ()
printCommonWords n filename = do
    handle <- openFile filename ReadMode
    contents <- hGetContents handle
    putStr (commonWords n contents)
    hClose handle

ここで、ちょうどPythonで同じことをしているコードがあるので比較してみる。
https://qiita.com/ground0state/items/ad1a66bee66ee276d8e5

リンク先のコードは、大文字小文字を区別しているのでdata = data.lower() のコメントアウトを外す。

文字カウントするテキストを落とす。

curl -OL https://www.gutenberg.org/cache/epub/8868/pg8868.txt

計算してみると、どちらも一致する。Pythonが一瞬で終わるのに対して、Haskell版はビルドしても計算に時間かかる。コードの方は、Haskellのほうが読みやすい。PythonでもHaskellっぽくも書けますよという人がいるかも知れない。

2730 the
1661 i
1454 to
1296 and
1250 of