Open48

haskell勉強

hayaohayao

Stringの代わりにData.Textを使うのがよい?

関数を探す

hoogle.haskell.org

hayaohayao

経験豊富な Haskeller は、まず型クラスを探し、それからコーディングを始めることが多い。

hayaohayao

ghc拡張が色々あるのでHaskellを使いこなすにはそれに詳しい必要がある

hayaohayao

POLYMORPHIC VALUES

C a => a型は多相的と呼ばれ、様々な形式で使える。

hayaohayao

コードが動かないときは考えられる原因を列挙する

hayaohayao

かなり難しく感じるが手続き型言語を初めて勉強したときも同じだったはず。
手続き型言語習熟者が新たな手続き型言語を習得するのと関数型言語を習得するのは難易度が全く違って当たり前

hayaohayao

ある程度基礎を学んだあとはなにで入門する?

候補

  • CLI
  • Webサーバー
  • 自作ライブラリ
hayaohayao

elmより普通に実行時エラーになる
実行時エラーになる関数がちょくちょくある
headやread等

hayaohayao

haskellで評判が悪いもの

  • 部分関数 結果が未定義(例外を投げる)引数の組み合わせがある
  • 遅延IO
hayaohayao

中級者への道

言語拡張を使えるようになる
データ型を型クラスのインスタンスにできるようになる
部分関数を避ける
packageを知る
computational context: functor, applicative, monadのなんとなく理解してコーディングができる
ghciコマンドが使える
hoogleを活用できる
Traversalが使いこなせる
lensを理解する

hayaohayao

ReadとShowのissue

Stringを連結して構築するのは非常に非効率的です。Show型クラスはかなり限定的な解決策を与えてくれますが、それについては後ほど説明します。

再帰的データ型には、括弧の問題があります。これについてもShow型クラスで対処しています。

手動で実装されたShowとの互換性を維持するためにReadインスタンスを実装するのは大変です。

hayaohayao

計算コンテキスト

Functor

値に対するマッピング fmap

Applicative

コンテキストに値を注入 pure
コンテキスト内の関数をコンテキスト内の値に適用 <*>

Monad

あるコンテキストでの計算を順番に実行し、次の計算で何が行われるか前の計算の結果に依存するようにする >>=

hayaohayao

Traversal

traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

構造を保ちながら(t aからt b)コンテキストをまとめる

ghci> traverse readMaybe ["1", "2", "3"] :: Maybe [Int]
Just [1,2,3]

hayaohayao

stockquotesアプリケーション作成する際のの課題

  • データ表現
  • CSVファイルのパース
  • レポートの書式設定
  • グラフの作成
  • UI設計
    • コマンドライン引数の扱い
    • 純粋部とIO部の区分け
      • IO部はなるべく小さく
hayaohayao

型クラスのヘビーユースはHaskellで極めて一般的なidiom

ライブラリは型クラスで制約や振る舞いを描写する

ライブラリを使うために型クラスを導出するのは我々の責任

hayaohayao

ビルド成功させるのムズくない?気のせい?

hayaohayao

preludeには非効率なStringや部分関数headなどがあるからcustom preludeを使ったほうがいいかも

  • protolude
  • relude
  • universum
hayaohayao

Reader モナド

情報を暗黙のうちに渡し、好きなときにアクセスできる効果を持った計算を定義する。これはまさに、Readerモナドが使われていることです。

hayaohayao
processLine :: (Int, Text) -> Writer [ErrorMsg] SQL
processLine (_, T.splitOn ":" -> [s1, s2]) = pure $ genInsert s1 s2
processLine (i, s) = tell [WrongFormat i s] >> pure ""

2行目: The ViewPatterns GHC extension

hayaohayao

Stateモナドは可変状態を持つ命令形のアルゴリズムの実装を容易にする

hayaohayao

複数のモナドを使いたいときってどうするの?

Monad transformers

type EvalM = stateT Stack Maybe

仕組みは分かっていない

多層にしたい場合は?
→入れ子にする

hayaohayao
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

MaybeT { runMaybeT :: m (Maybe a) }はどういう意味?

MaybeTは値コンストラクタ

runMaybeT というフィールドを持ちその型は m (Maybe a)

hayaohayao
instance Applicative m => Applicative (MaybeT m) where
  pure :: a -> MaybeT m a
  pure a = MaybeT (pure $ Just a)

  (<*>) :: MaybeT m (a -> b) -> MaybeT m a -> MaybeT m b
  (MaybeT mf) <*> (MaybeT mx) = MaybeT ((<*>) <$> mf <*> mx)

(MaybeT mf) <*> (MaybeT mx) = MaybeT ( [(<*>) <$> mf ] <*> mx )
[(<*>) <$> mf ] : m (Maybe a -> Maybe b)
mx : m (Maybe a)
<*>: m (Maybe a -> Maybe b) -> m (Maybe a) -> m (Maybe b)

型パズルすぎる。。直感的に理解できない😭

hayaohayao

持ち上げ

instance MonadTrans MaybeT where
  lift :: Monad m => m a -> MaybeT m a
  ...
hayaohayao

詳しく知りたい

MonadFail

実装するとパターンマッチングの失敗に対応できる?

MonadPlus

hayaohayao

monad transformer in haskell libarary

transformers
mtl

hayaohayao

State

状態を変化させる関数を持つ
s -> (s, a)

hayaohayao

Monad Transformer

とりあえず内部実装は置いておいて関数の動作を把握する

Archiver はStateT

evalStateTはStateTと状態をとって、内側のモナドに値aを適用した値を返す
runXXX系 newtypeでwrapしたものを返す
Stateのget モナドの中の現在の状態値を取得する←状態はどこから来る? paserCharの使われ方を見る
put :: Monad m => s -> StateT s m () 状態をsにする

State
runState :: s -> (s, a)

StateT
runStateT :: s -> m (a, s)

liftStateT :: Monad m => m a -> StateT s m a
liftStateT a = StateT $ \s -> (, s) <$> a
あるモナド値をそれを状態としてもつ、StateTにする。

do記法が使われているときに、それがどのモナド下で起こっているかの判断はその関数の戻り値でする?

ExceptT (m (Either e a))

throwError :: Monad m => e -> ExceptT e m a
throwError exception = ExceptT (pure $ Left exception)
あるエラーをそれをLeftにもつExceptT値にする

newtype:内部が関数のものと普通の値のものがある

新たな抽象的概念が登場するたび、以下が必要になる

  • 理論を理解する
  • 使って慣れる

わかってない

Monad Trasfomerの重ねる順番の挙動への影響

guessTheState :: String -> GuessingGame Bool
guessTheState guess = do
answer <- get
put guess
pure $ guess == answer

hayaohayao

遅延評価のメモ化は独特。。
以下の用な感じでメモテーブル作ってlookupで計算していく。遅延評価だからdistanceを定義した段階だとサンクの状態である

distances =
map (\idxA -> map (getEditDistance idxA) [0..bLen]) [0..aLen]