CPS
CPS
による階乗計算
> :{ | fac 0 k = k 1 | fac n k = fac (n-1) $ \res -> k $ (*) n res | :} > fac 3 id 6 > fac 3 (+1) -- (1 * 2 * 3) + 1 7
手計算してみる。
fac 3 k = fac 2 $ \res -> k $ (*) 3 res = fac 1 $ \res1 -> (\res -> k $ (*) 3 res) $ (*) 2 res1 = fac 0 $ \res1 -> (\res -> k $ (*) 3 res) $ (*) 2 res1 = (\res1 -> (\res -> k $ (*) 3 res) $ (*) 2 res1) 1 = (\res -> k $ (*) 3 res) $ (*) 2 1) = \res -> k $ (*) 3 res $ 2 = k $ (*) 3 2) = k $ 6
stackのghciをテスト側で開く
通常のghci
で開くとlib
またはexe
側でghci
が開く
$ stack ghci
テスト側で開きたい時はテストスイート名を明示的に指定する。
$ stack ghci :RFC5646-test
stackでテストスイートを個別に実行する
name: hoge tests: foo-test: main: Spec.hs source-dirs: test bar-doctest: main: test/doctests.hs
と2つのテストスイートfoo-test
とbar-doctest
を定義する。
このときstack test
でテストが実行されるが、両方とも実行される。
片方だけ実行したい場合は
> stack test hoge:foo-test
> stack test hoge:bar-doctest
パッケージが1つだけであれば省略できる。
> stack test :foo-test
> stack test :bar-doctest
Applicative Mabyeで条件分岐
なんらかのデータを取得する処理をして、あればそれを使い、なければ、別途データを取得する
というロジックは、よくあるのではないでしょうか。
例えば、このような場合です。
import qualified Data.HashMap.Lazy as HML m = HML.fromList [("k1", "**"), ("k2", "##")] foo x1 x2 = case HML.lookup x1 m of Just a1 -> Just a1 Nothing -> case HML.lookup x2 m of Just a2 -> Just a2 Nothing -> Nothing
キーを二つ用意して、最初のキーで情報が見つかれば、それを使い、見つからなければ、二番目のキーを使います。
lambda > foo "k1" "k2" Just "**" lambda > foo "k1_" "k2" Just "##" lambda > foo "k1_" "k2_" Nothing
case
が2つあって冗長です。
Maybe
モナドでa >>= b
とすると、a
がJust
のときに、b
に移ります。が、やりたことはこの逆で、Nothing
だったらb
に移るということです。このような時はApplicative
を使うと良さそうです。
foo'' x1 x2 = HML.lookup x1 m <|> HML.lookup x2 m
lambda > foo'' "k1" "k2" Just "**" lambda > foo'' "k1_" "k2" Just "##" lambda > foo'' "k1_" "k2_" Nothing
Contravariant
covariant functor ~~> produce something contravariant functor ~~> consume something
(>$) = contramap . const const :: a -> b -> a contramap :: Contravariant f => (a -> b) -> f b -> f a contrampa . const = x -> y -> x (a -> b) -> f b -> f a = x -> f b -> f a ( y = a , x = b ) = b -> f b -> f a
lambda > import Data.Functor.Contravariant lambda > data Person = Person {balance :: Int} lambda > let personBankBalance p = balance p lambda > let negative = Predicate (\x -> x < 0) lambda > lambda > overdrawn = contramap personBankBalance negative :: Predicate Person lambda > lambda > getPredicate overdrawn (Person 5) False lambda > getPredicate overdrawn (Person (-10)) True lambda > lambda > overdrawn' = (>$) (-15) negative lambda > getPredicate overdrawn' (Person 5) True lambda > getPredicate overdrawn' (Person (-10)) True