2013-05-25 6 views
5

は、なぜこの関数はタイプがありますか?ここでなぜ私の関数の戻り値として入れ子になったIOモナドIO(IO())がありますか?それは単純な定義を持っているなるようにどのように私はこれを書き換えることができ、 <code>deleteAllMp4sExcluding :: [Char] -> IO (IO()) </code>代わりにまた</p> <p><code>deleteAllMp4sExcluding :: [Char] -> IO()</code>の:

は、関数の定義である:IO Sに適用した場合に

import System.FilePath.Glob 
import qualified Data.String.Utils as S 

deleteAllMp4sExcluding videoFileName = 
    let dirGlob = globDir [compile "*"] "." 
     f = filter (\s -> S.endswith ".mp4" s && (/=) videoFileName s) . head . fst 
     lst = f <$> dirGlob 
    in mapM_ removeFile <$> lst 

答えて

16

<$>(a -> b) -> IO a -> IO bを入力しています。したがって、mapM_ removeFile[FilePath] -> IO()タイプなので、bIO()なので、結果タイプはIO (IO())になります。

このようなネストを避けるには、適用しようとしている機能がIOという値の場合は<$>を使用しないでください。むしろ>>=を使用するか、オペランドの順序を変更しない場合は=<<を使用してください。

+0

私の直感的な感想: 'removeFile'は1つの効果を追加します。最後に1つのエフェクトが必要な場合は、0の効果があるものをフィードしなければなりません。 'lst'はすでに効果があります。最初にそれを削除する必要があります。bind(演算を実行する)を使用して効果を実行し、0効果で値を取得します – nicolas

8

sepp2kの回答では、これはFunctorMonadの違いを示す優れた例です。

Monadの標準Haskellの定義は、この(簡体字)のようなものになる:

class Monad m where 
    return :: a -> m a 
    (>>=) :: m a -> (a -> m b) -> m b 

しかし、これはクラスが定義されていることができる唯一の方法ではありませんが。あなたはfmapjoinの面で>>=を定義することができることを考えると

class Functor m => Monad m where 
    return :: a -> m a 
    join :: m (m a) -> m a 

:代替は次のように実行します

(>>=) :: Monad m => m a -> (a -> m b) -> m b 
ma >>= f = join (f <$> ma) 

私たちは、あなたがしている問題の単純化されたスケッチで、このを見てみましょうに走っている。あなたがIO bを必要とするので

ma  :: IO a 
f  :: a -> IO b 
f <$> ma :: IO (IO b) 

は、今あなたが立ち往生している、と Functorクラスが IO (IO b)からそこにあなたを取得します何も操作を持っていない:あなたがやっていることは、次のように図式化することができます。あなたがしたい場所を取得する唯一の方法は、 Monadに浸すことであり、 join操作は、それを解決し、正確に何である: >>=

join (f <$> ma) :: IO b 

しかしjoin/<$>によって定義、これは同じです:

ma >>= f :: IO a 

Control.Monadライブラリには、joinreturn(>>=)で書かれています)のバージョンが付属しています。それをあなたの関数に入れて、あなたが望む結果を得ることができます。しかし、より良いことは、あなたがしようとしていることが基本的にモナドであることを認識することです。したがって、<$>は仕事のための適切なツールではありません。ある行動の結果を別の行動に移しています。本質的にはMonadを使用する必要があります。

関連する問題

 関連する問題