Haskell: Scan Through a List and Apply A Different Function for Each Element

前端 未结 4 1943
我寻月下人不归
我寻月下人不归 2021-02-06 11:43

I need to scan through a document and accumulate the output of different functions for each string in the file. The function run on any given line of the file depends on what i

4条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-06 12:01

    It is a good idea to introduce a new ADT, e.g. "Summary" instead of tuples. Then, since you want to accumulate the values of Summary you came make it an istance of Data.Monoid. Then you classify each of your lines with the help of classifier functions (e.g. isAtom, isSheet, etc.) and concatenate them together using Monoid's mconcat function (as suggested by @dave4420).

    Here is the code (it uses String instead of ByteString, but it is quite easy to change):

    module Classifier where
    
    import Data.List
    import Data.Monoid
    
    data Summary = Summary
      { atoms :: [String]
      , sheets :: [String]
      , digits :: [String]
      } deriving (Show)
    
    instance Monoid Summary where
      mempty = Summary [] [] []
      Summary as1 ss1 ds1 `mappend` Summary as2 ss2 ds2 =
        Summary (as1 `mappend` as2)
                (ss1 `mappend` ss2)
                (ds1 `mappend` ds2)
    
    classify :: [String] -> Summary
    classify = mconcat  . map classifyLine
    
    classifyLine :: String -> Summary
    classifyLine line
      | isAtom line  = Summary [line] [] [] -- or "mempty { atoms = [line] }"
      | isSheet line = Summary [] [line] []
      | isDigit line = Summary [] [] [line]
      | otherwise    = mempty -- or "error" if you need this  
    
    isAtom, isSheet, isDigit :: String -> Bool
    isAtom = isPrefixOf "atom"
    isSheet = isPrefixOf "sheet"
    isDigit = isPrefixOf "digits"
    
    input :: [String]
    input = ["atom1", "sheet1", "sheet2", "digits1"]
    
    test :: Summary
    test = classify input
    

提交回复
热议问题