2011-12-24 14 views
5

私はハスケルを初めとし、いくつかのコンセプトを頭で囲むのにはいくつかの困難を抱えています。IO [[文字列]]をフラット化する方法は?

IOで遊んでいる間にIO [[String]]を平坦化したかったのです。

私が試したものの一例:

予想通りGHCiの中 [[String]]で動作します
module DatabaseTestSO where 

import Database.HDBC 
import Database.HDBC.MySQL 
import Data.Foldable 

convSqlValue :: [SqlValue] -> [String] 
convSqlValue xs = [ getString x | x <- xs ] 
    where getString value = case fromSql value of 
       Just x -> x 
       Nothing -> "Null" 

listValues :: [[SqlValue]] -> [[String]] 
listValues [] = [] 
listValues xs = [ convSqlValue x | x <- xs ] 

flatten :: [[a]] -> [a] 
flatten = Data.Foldable.foldl (++) [] 

domains :: IO [[String]] 
domains = 
    do conn <- connectMySQL defaultMySQLConnectInfo { 
       mysqlHost  = "hostname", 
       mysqlDatabase = "dbname", 
       mysqlUser  = "username", 
       mysqlPassword = "pass" } 

     queryDomains <- quickQuery conn "SELECT name FROM domains" [] 

     return (listValues queryDomains) 

を:

*DatabaseTestSO> flatten [["blah","blab","wah"],["bloh","blob","woh"],["blih","blib","wuh"]] 
["blah","blab","wah","bloh","blob","woh","blih","blib","wuh"] 

しかしIO [[String]]で、私は

*DatabaseTestSO> flatten domains 

<interactive>:1:9: 
    Couldn't match expected type `[[a0]]' 
       with actual type `IO [[String]]' 
    In the first argument of `flatten', namely `domains' 
    In the expression: flatten domains 
    In an equation for `it': it = flatten domains 

を得ることはありませんIO型で純粋であるはずの関数を使うことはできないと思いますか? IO [[String]][[String]]に変更できますか? この問題を正しく解決するにはどうすればよいですか?

+4

'flatten'は' concat'と呼ばれ、 'Prelude'で定義されています。 –

+0

私は参照してください。 GHCiを使用しない場合、 'Prelude'は自動的にインポートされますか? –

+0

はい(フィラー...) –

答えて

15

IO somethingの意味を理解しておく必要があります。 somethingではなく、のアクションで、something(この場合、something[[String]])を返します。したがって、アクションを実行するまでアクションが返すものは何もできません。そのアクションを実行すると、そのアクションが返されます。

問題を解決する方法は2つあります。

  1. アクションを実行し、結果を使用します。これは次のように行われます。

    do 
        ds <- domains  -- Perform action, and save result in ds 
        return $ flatten ds -- Flatten the result ds 
    
  2. いくつかのアクションの結果を受け取り、それに関数を適用する新しいアクションを作成します。新しいアクションは変換された値を返します。これは、Control.MonadモジュールのliftM関数で行われます。

    import Control.Monad 
    -- ... 
    
    do 
        -- Creates a new action that flattens the result of domains 
        let getFlattenedDomains = liftM flatten domains 
    
        -- Perform the new action to get ds, which contains the flattened result 
        ds <- getFlattenedDomains 
    
        return ds 
    

PS。あなたが何をするかを明確にするためにdomains変数の名前をgetDomainsに変更したいと思うかもしれません。それは純粋な価値ではありません。それは純粋な価値を返すモナドな行動です。

+0

あなたの説明はとても役に立ちました。 –

+3

注: 'fmap' =' liftM' = 'liftA' =' <$> 'です。 –

10

IOから何も出ることはできません。そのためには、flattenを持ち上げてください。これを行う最も簡単な方法はfmapです。mapがリスト上の関数を適用するのと同じように、fmapは、などの任意のFunctorインスタンス上の関数を適用します。

flattenIO xs = fmap flatten xs 

は、より一般的なケースでは、あなたはIO計算で物事を取得するためにdo表記を使用することができます。たとえば、次のように

flattenIO xs = do ys <- xs 
        return (flatten ys) 

...この場合にはfmapを書くだけ回り道です。

+0

お返事ありがとうございます。私はたくさんのことを学ばなければならないでしょう。 –

関連する問題