2016-05-17 6 views
4

私はちょうどハスケルを学び始めました。ハスケルで関数とモナドの動作を構成する方法

私は重複ファイルを見つけるプログラムを作成しています。私が対処する方法を見つけることができません

:私は、以下の機能作成しました:

hashFile :: (MonadIO m) => FilePath -> m (Digest MD5) 
categorize :: Ord k => (a -> k) -> [a] -> Map.Map k [a] 

をそして私は

Map.Map (Digest MD5) [FilePath]

私の質問がある返す機能でそれらを構成したいです私が望むものを得るためのIOモナド。だから、私の質問は以下のとおりです。

  1. は、私が正しいをやろうとしている、または戻り値の型は 本当にMap.Map (IO (Digest MD5)) [FilePath]になりべきものです。

  2. ハッシュでグループ化されたファイルのリストを取得するには、これらの関数を一緒に作成するにはどうすればよいですか?

+2

1.あなたは 'FilePath - > IO(Digest MD5)'を持っています。 '[IO(Digest MD5、FilePath)]'リストを構築する// 3. Traversableクラスを使って 'IO [(FilePath) [Digest MD5(FilePath)]) – hao

答えて

6

てみましょう慎重ので、チェックを入力しないであろうcategorize

hashFile ::    FilePath -> IO (Digest MD5) -- I simplified the MonadIO constraint 
categorize :: Ord k => ( a ->  k  ) -> [a] -> M.Map k [a] 

categorize hashFileに引数としてhashFileを渡すために私たちが望むことを念頭に、categorizeの種類とhashFileのタイプを比較しGHC kIO (Digest MD5)に一致させようとしますが、IOにはOrdインスタンスがありません。言い換えれば、IO (Digest MD5)Mapの鍵として役に立たない:あなたが必要とするのはDigest MD5であり、実行すると最終的にはDigest MD5を生成する計算ではない。

IOの計算をすべて実行し、その結果(タイプDigest MD5)をMapに入力してください。結果の関数はIO (Map (Digest MD5) FilePath) - IOの計算を返し、実行するとMap (Digest MD5) FilePathを返します。


これを行う最も簡単な方法は、必要なタイプに合わせてcategorizeを調整することです。

categorize :: (Applicative f, Ord k) => (a -> f k) -> [a] -> f (M.Map k a) 
categorize f = fmap M.fromList . traverse (\x -> fmap (, x) (f x)) 

(私はTupleSectionsを使用しています)まずタイプを見てみましょう。 IOApplicativeのインスタンスであるので、(a -> f k)は、以下の制約の下でFilePath -> IO (Digest MD5)で統一:私たちが望むタイプです

a ~ FilePath 
f ~ IO 
k ~ Digest MD5 

のでcategorize hashFile :: [FilePath] -> IO (M.Map (Digest MD5) FilePath)、。

ここで実装を見てみましょう。 traverse :: Applicative f => (a -> f b) -> [a] -> f [b] *(nee mapM)はApplicative関数を受け取り、それをリストにマップし、結果をまとめてリストにします。各アイテムを(result, item)タプルに変換するために使用しています。これによりf [(k, a)]値が生成されます。そして、 M.fromListの結果がf (M.Map k a)になります。

*技術的には、traverseは、より一般的なタイプの(Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)です。私はt ~ []を取ってこのバージョンに着いた。

この実装ではM.fromListが使用されるため、重複した項目が破棄されます。実際には、ファイルの内容が同じであることを期待していない場合は、MD5のハッシュが異なるため問題ありません。練習問題:重複を維持したい場合、これはどのように変化しますか?

+0

@AndPos: "モナドでの作業方法を理解できました"ここで重要な点の1つは、このためにモナドを必要としない*必要ではないことです。適用可能なファンクタで十分です。 – Cactus

+0

@Cactus私はこれが重要な点だと私は反対します。それは要点ですが、これは微妙なものであり、アプリケーションの99%についてはおそらく重要ではありませんが、実行する必要のある 'IO'を使用するための' Monad'関連インタフェースの使い方を理解することの重要性有用なアプリケーションの100%で –

+2

@DanielWagner:私は、モナドのインターフェースは初心者のマテリアルでは過度に表現されていると思うので、私は応用的なものを主張する機会を逃すことはありません。 – Cactus

関連する問題