2011-12-24 30 views
5

Tôi mới sử dụng Haskell và có một số khó khăn trong đầu của tôi xung quanh một số khái niệm của nó.Làm thế nào để san bằng IO [[String]]?

Khi phát xung quanh với IO, tôi muốn làm phẳng một IO [[Chuỗi]].

Một ví dụ về những gì tôi đã cố gắng:

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) 

đó làm việc với [[String]] trong GHCi như mong đợi:

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

nhưng không với IO [[String]] nơi tôi nhận

*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 

Tôi đoán tôi không thể sử dụng một chức năng được cho là tinh khiết với các loại IO? Tôi có thể chuyển đổi IO [[String]] thành [[String]] không? Làm cách nào để giải quyết vấn đề này một cách chính xác?

+4

'flatten' được gọi là' concat' và được xác định trong 'Prelude'. –

+0

Tôi hiểu. 'Prelude' được nhập tự động khi không sử dụng GHCi? –

+0

Có (phụ ...) –

Trả lời

15

Bạn phải nhận ra ý nghĩa của IO something. Đây không phải là something, đó là hành động sẽ trả lại something (Trong trường hợp này, something[[String]]). Vì vậy, bạn không thể làm bất cứ điều gì với những gì mà hành động trả về, cho đến khi bạn thực hiện các hành động, mà trả về điều đó.

Bạn có hai tùy chọn để giải quyết vấn đề của mình.

  1. Thực hiện tác vụ và sử dụng kết quả. Điều này được thực hiện như sau:

    do 
        ds <- domains  -- Perform action, and save result in ds 
        return $ flatten ds -- Flatten the result ds 
    
  2. Tạo một hành động mới có kết quả của một số hành động và áp dụng chức năng cho hành động đó. Hành động mới sau đó trả về giá trị được chuyển đổi. Điều này được thực hiện với chức năng liftM trong mô-đun Control.Monad.

    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. Bạn có thể muốn đổi tên biến số domains thành getDomains để làm rõ biến số của nó. Nó không phải là một giá trị thuần khiết; đó là một hành động đơn thuần trả về giá trị thuần túy.

+0

Giải thích của bạn rất hữu ích. –

+3

Lưu ý: 'fmap' =' liftM' = 'liftA' =' <$> '. –

10

Bạn không thể lấy bất cứ thứ gì "out" của IO, vì vậy những gì bạn cần làm là nâng flatten để làm việc bên trong nó. Cách đơn giản nhất để thực hiện việc này là fmap - điều chỉnh như map áp dụng một chức năng trong danh sách, fmap áp dụng một chức năng trên bất kỳ trường hợp Functor nào, chẳng hạn như IO.

flattenIO xs = fmap flatten xs 

Trong trường hợp tổng quát hơn, bạn có thể sử dụng do ký hiệu để có được vào những điều trong IO tính toán. Ví dụ:

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

... chỉ là cách viết vòng fmap trong trường hợp này.

+0

Cảm ơn bạn đã trả lời. Tôi sẽ phải học rất nhiều. –

Các vấn đề liên quan