2016-08-23 6 views
6

ハスケルでforM_の使用に陥る傾向があります。これはRubyでは.each、Scalaではforeachと非常によく似ています。`forM_`はハスケルですね?

import Control.Monad (forM_) 
import Network.BSD (getHostByName, hostAddresses) 
import Network.Socket (inet_ntoa) 
import System.Environment (getArgs) 

resolve address = do 
    ent <- getHostByName address 
    mapM inet_ntoa (hostAddresses ent) 

main = do 
    args <- getArgs 
    args `forM_` (\address -> do 
    ips <- resolve address 
    ips `forM_` (\ip -> putStrLn $ address ++ "\t" ++ ip)) 

私には慣用的であるように見えるが、mapM_を使用すると、不器用なようではありません。このコードを書き直す慣用方法はありますか?

+1

ない重複したが、私は、私は[ここに私の答え]感じる感じますhttp://stackoverflow.com/questions/16726659/should-do-notation- be-avoided-in-haskell/16733658#16733658)はこれをかなりうまく扱っています。私は_itがそれのように 'forM_'を使うのはまったくいいと言っています。 (phadejが言うように、 'for_'はより現代的な選択肢ですが、実際には、通常はこれらの間に違いはありません。) – leftaroundabout

答えて

10

ただfor_ :: (Foldable t, Applicative f) => t a -> (a -> f b) -> f()からData.Foldableを使用する方が良いでしょう。

main = do 
    args <- getArgs 
    for_ args $ \address -> do 
     ips <- resolve address 
     for_ ips $ \ip -> putStrLn $ address ++ "\t" ++ ip 

P.S.:プレフィックス(すなわち、正常な機能)として使用することによっても

、コードが「通常」命令型コードのように見えますMonad IC "トラバース" のApplicativeバージョン:

  • mapMtraverse
  • mapM_traverse_
  • forMfor
  • forM_for_
+1

これらの操作は本質的に' Applicative'です。より自然にモナドなバージョンがあります。 'traverseM ::(Monad m、TraversableM t)=>(s-> a-> m(s、b)) - > t a-> m(t b)'である。後者は 'StateT'を使って' Traversable'に強制することができますが、私はMcBrideスタイルのインデックス付きモナドが必要な時には動作しなくなることは間違いありません。 – dfeuer

+0

ニースの答え!まさに私が探していたもの!おそらく –

1
main = getArgs >>= mapM_ (\address -> 
    resolve address >>= mapM_ (\ip -> 
    putStrLn $ address ++ "\t" ++ ip)) 

そして、ArgumentDoを取得したら、そのラムダ式をかっこにする必要はありません。

ListTにも適用できることが起こる:(

main = void $ runListT $ do 
    address <- ListT getArgs 
    ip <- ListT $ resolve address 
    liftIO $ putStrLn $ address ++ "\t" ++ ip 
+0

'mapM_'でしょう。私はここでコードゴルフが本当に役に立つとは思わない。 – phadej

+0

これは 'typechecking xの' mapM_'ありがとう) – Gurkenglas

+0

'アドレスはどこから来たのですか? –