2017-02-20 6 views
2

私は、 "リストのような"シーケンスを作成するライブラリを作っており、多くのPreludeスタイル関数が実装されています。私のライブラリが正しい出力を出すためのテストケースをいくつか書きたいと思います。これを行う最も簡単な方法は、いくつかの関数を書いて結果をリストに変換し、Preludeの結果と比較することです。我々はこれを持って言うことができます:異なるタイプのHaskellでのテストケースの作成

import qualified MyLibrary as ML 
import qualified Prelude as P 

は、例えば、私は、次のテストケースをしたいことがあります。ML.enumFromはない出力リストを行い

P.take 5 (P.enumFrom 1) == toList (ML.take 5 (ML.enumFrom 1)) 

注こと、それはそれ自身のデータ型を出力します。

上記はうまくいきますが、私が「自分自身を繰り返している」ことに気づくでしょう(TM)。私はテストケースが間違っていなければ、左右が同じであることを保証する必要があります。

このようなテストケースを書く良い方法があるので、自分自身を繰り返す必要はありませんか?

+1

2つのメカニズムを比較するためにテストが定義上「自分自身を繰り返す」場合は、実際に「自分自身を繰り返す」とは思わないのです。 –

+0

理想的には、すべてのテストはどの関数を使うかを決めるパラメータを取るので、 'doTest test = test True == toList(test False)'のような 'doTest'関数を使うことができますが、型チェッカーが私を嫌うことなくこれを行う方法を見つけました。 – Clinton

+0

@Clinton:私は、共通の 'クラス 'をインスタンス化せず、テンプレートhaskell(これは私が経験していないもの)を使用すると、それを達成できないと思います – jakubdaniel

答えて

1

P.takeML.takeなどの最初の問題は、類似しているに過ぎません。実際、それらはまったく関係のない関数であり、コンパイラは共通の動作について何も知らないのです。 @ jd823592が提案されているように、我々は型クラス(例はコンパイルになるので、私はシンプルなnewtypeラッパーを使用)を持つグループにそれらを必要とする:

import Prelude hiding (take, enumFrom) 
import qualified Prelude as P (take, enumFrom) 

newtype MySeq a = MySeq [a] 

class Sequence s where 
    take :: Int -> s a -> s a 
    enumFrom :: Enum a => a -> s a 
    toList :: s a -> [a] 

instance Sequence MySeq where 
    take n (MySeq xs) = MySeq (P.take n xs) 
    enumFrom n = MySeq (P.enumFrom n) 
    toList (MySeq xs) = xs 

instance Sequence [] where 
    take = P.take 
    enumFrom = P.enumFrom 
    toList = id 

その後、我々は今、統一を使用して、いくつかのテストを定義してみましょう関数をクラス定義から削除します。彼らはどんなタイプのSequenceも生成するかもしれません、そして、我々は明示的な型を生成するように強制します。

test1 = doTest (take 5 $ enumFrom 1) -- the part in brackets is polymorphic 

doTest :: (Eq a, Sequence s) => s a -> Bool 
doTest test = ??? 

次に第二の問題は、我々は、パラメータとして多型の機能を通過した後、異なる種類のパラメータ(この場合[a]MySeq a)とそれをインスタンス化する必要があることです。標準Haskellの2010年には、それは不可能ですが、私たちはRank2 (or RankN) extensionを利用することができます。

{-# LANGUAGE Rank2Types #-} 

<...> 

doTest :: forall a . Eq a => (forall s . Sequence s => s a) -> Bool 
doTest test = (test `asTypeOf` dummy1) == toList (test `asTypeOf` dummy2) where 
    dummy1 :: Eq a => [a] 
    dummy1 = undefined 
    dummy2 :: Eq a => MySeq a 
    dummy2 = undefined 

このソリューションは、少し不器用ですが、まだ動作します。気軽に改善してください。

関連する問題