何故正規表現を使いたく無いかよく分かって無いですが,ワイドルカードや許容文字が複数ある場合などは,
regex-applicative-text
や regex-tdfa
などをよく使いますregex-applicative-text
や regex-tdfa
などをよく使いますTypeable
のインスタンス解決が破綻してる件ってどうなってるんでしょうか? DeriveDataTypeable
はお亡くなりになる感じなのか,それともderiving自体は現状でも書いておくべきなんでしょうか?Typeable
でderivingされたものは無視するという方針でいく感じですかね? そうなると現状, AutoDeriveTypeable
が有効になってる前提で書くのがいいのか, DeriveDataTypeable
でいちよderivingを書いていくのがいいのかどっちなんですかね?instance Arbitrary
ってライブラリ側に書くのとテスト側に orphan instance として書くの、どちらがいいんでしょう。{-# OPTIONS_GHC -fno-warn-orphans #-}
を書いておきます。imperative-edsl
の System.IO.Fake
モジュールで定義されている fakeIO
関数を使ってこんな感じのテストを書いてみたんですが、他の方法って何かあります?module Main where import System.IO.Fake (fakeIO) import Test.Hspec (hspec, describe, it) import Test.Hspec.Expectations (shouldReturn) main = hspec $ describe "Prelude.head" $ it "returns the first element of a list" $ fakeIO act "Haskell" `shouldReturn` "('H','a')\n" act :: IO () act = do x <- getChar getChar y <- getChar print (x, y)
Failures: Main.hs:10: 1) Prelude.head returns the first element of a list expected: "('H','a')\n" but got: "('H','s')\n"
IO ()
をテストする他の方法という意味ですー。IO
している関数に手を入れることができるなら、 :point_down: こういうちょっとした依存性注入パターンを使いますね。data Env m = Env { print :: String -> m (), read :: m String } useIo :: Monad m => Env m -> m () useIo e = do s <- read e print s
IO
するかどうかを Env
の中身に委ねつつ、 useIo
を実質純粋な関数として維持できます。Env
を ReaderT
を経由して渡すようにすれば、見かけとしてもバッチリになるでしょう。silently
パッケージというのもあります。stdout
を再オープンして書き換える、という大胆不敵なやり方をとっています。module Main where import Data.Conduit (ConduitM, await, yield, runConduit, runConduitPure, (.|)) import qualified Data.Conduit.List as CL import Conduit (stdinC, stdoutC) import Data.ByteString.Char8 (pack, unpack) import Test.Hspec (hspec, describe, it) import Test.Hspec.Expectations (shouldBe) main = hspec $ describe "Prelude.head" $ it "returns the first element of a list" $ runConduitPure (CL.sourceList "Haskell" .| act .| await) `shouldBe` Just ('H','a') act :: Monad m => ConduitM Char (Char, Char) m () act = do Just x <- await await Just y <- await yield (x, y) actIO :: IO () actIO = runConduit $ stdinC .| CL.concatMap unpack .| act .| CL.map (pack . show) .| stdoutC
MIN_VERSION_*
で4桁を指定する方法ってないですよね?hoge-1.2.3.4
と hoge-1.2.3.5
で振る舞いを分ける方法って無いですよね?fakeIO
の実装は silently
にインスパイアされたものなので、仕組み自体は silently
に近いです。Env
を使った依存性注入パターンでは、例えば通常 putStrLn
を使って出力している箇所を Env
の print
に差し替える必要がありそうですね。このやり方に近い感じですか?
https://lexi-lambda.github.io/blog/2017/06/29/unit-testing-effectful-haskell-with-monad-mock/
Env
を implicit に渡していると考えれば近いかと思います。Env
は直接渡した方が、型クラスより柔軟でお勧めです。テスト可能な形で入出力を切り離す
というよりは、既存のコードをできるだけ変更せずにテストするためにはどうしたら良いのかな?という感じでした。 (ちゃんと明示してなくてすみません。)Conduit
あまり詳しく無いのですが、こういうこともできるんですね。勉強になりました。ありがとうございます。hoge <=1.2.3.4
に依存するか hoge >=1.2.3.5
に依存するかのフラグを定義して、それに応じて CPP-Options:
を設定する、という手はありますが。flag hogefuga-new-version default: True manual: False library ... (snip) if flag(hogefuga-new-version) build-depends: hogefuga >= 1.2.3.5 cpp-options: -DHOGEFUGA_NEW_VERSION else build-depends: hogefuga >= 1 && < 1.2.3.5
hogefuga-new-version
フラグを cabal build のときに渡して切り替える感じですか?replicate 100 False
で作成したリストに対して、mkcs :: Int -> [Bool] mkcs n = [if (x`mod`n==0)then True else False|x<-[1..100]]
turn :: ([Bool],Int) -> ([Bool],Int) turn (cs.n) | n == 100 = (nxt,100) | otherwise = turn (nxt,(n+1)) where nxt = zipWith xor cs (mkcs n) xor a b = ((not a)&&b) || (a&&(not b)) main = do let c = replicate 100 False print turn (c, 2)
mkcs
の定義自体は mkcs n = [x
mod` n == 0 | x <- [1..100]]` でも良いですよねands
じゃなくて turn
??nxt = zipWith and cs (mkcs n)
も nxt = zipWith (&&) cs (mkcs n)
かな?False
だと何べん (&&)
しても False
だからなにしたいコードかよくわからないですね...turn :: ([Bool], Int) -> ([Bool], Int) turn = until ((> 100) . snd) (\(cs, n) -> (zipWith xor cs (mkcs n), n + 1))
[Bool]
だけだったら普通に畳み込みでいいのかimport Data.Bits main = print $ turn [2..100] (replicate 100 False) turn :: [Int] -> [Bool] -> [Bool] turn ns cs = foldl (\cs' n -> zipWith xor cs' (mkcs n)) cs ns mkcs :: Int -> [Bool] mkcs n = [x `mod` n == 0 | x <- [1..100]]
module Main where import Control.Arrow ((***)) import Data.Bool (bool) main :: IO () main = print (fromEnum <$> mkes 100) mkes :: Int -> [Bool] mkes b = hylo ((:) . mke b) [] phi b where phi 0 = Nothing phi n = Just (succ (b - n), pred n) mke :: Int -> Int -> Bool mke b m = hylo xor False phi b where phi 0 = Nothing phi n = Just (m `mod` succ (b - n) == 0, pred n) hylo :: (a -> b -> b) -> b -> (c -> Maybe (a, c)) -> c -> b hylo f e phi x = maybe e (uncurry ($) . (f *** hylo f e phi)) (phi x) xor :: Bool -> Bool -> Bool xor p q = bool p (not p) q