【问题标题】:haskell word searching program developmenthaskell 词搜索程序开发
【发布时间】:2011-09-05 12:44:46
【问题描述】:

你好,我正在做一些单词搜索程序

例如

当“text.txt”文件包含“foo foos foor .. foo傻瓜”时

然后搜索“foo”

然后只打印数字 2

反复搜索

但我是haskell初学者

我的代码在这里

:module +Text.Regex.Posix
putStrLn "type text file"
filepath <- getLine
data <- readFile filepath

--1. this makes <interactive>:1:1: parse error on input `data' how to fix it?

parsedData =~ "[^- \".,\n]+" :: [[String]]

--2. I want to make function and call it again and again
searchingFunc = do putStrLn "search for ..."
        search <- getLine
        result <- map (\each -> if each == search then count = count + 1) data
        putStrLn result
        searchingFunc
}

抱歉,代码非常糟糕

我的开发环境是 Windows XP SP3 WinGhci 1.0.2

对不起,我在几个小时前启动了 haskell

非常感谢您的阅读!

编辑:这里是原始方案代码

谢谢!

#lang scheme/gui
(define count 0)
(define (search str)
  (set! count 0)
  (map (λ (each) (when (equal? str each) (set! count (+ count 1)))) data)
  (send msg set-label (format "~a Found" count)))   

(define path (get-file))
(define port (open-input-file path))
(define data '())
(define (loop [line (read-line port)]) 
  (when (not (eof-object? line))
    (set! data (append data 
                       (regexp-match* #rx"[^- \".,\n]+" line)))
    (loop)))
(loop)
(define (cb-txt t e) (search (send t get-value)))
(define f (new frame% (label "text search") (min-width 300)))
(define txt (new text-field% (label "type here to search") (parent f) (callback (λ (t e) (cb-txt t e)))))
(define msg (new message% (label "0Found           ") (parent f)))
(send f show #t)

【问题讨论】:

  • 我明白了,您在 REPL 上输入了该代码。 Haskell 不是脚本语言(尽管你可以用它来编写脚本),编写代码的常用方法是将其放入后缀为 .hs 的文件中。
  • 非常感谢您的建议。还有什么?
  • 不要使用data 作为标识符。它是 Haskell 中引入新数据类型的保留字。
  • 哦!我知道了。再次感谢你
  • 另外一点是,Haskell 中的数据是不可变的。这意味着,像 count = count + 1 这样的东西是被禁止的,因为在 Haskell 中重新定义变量的值没有任何意义。

标签: function haskell recursion ghci


【解决方案1】:

请一步一步开始。 Haskell 中的 IO 是hard,所以你不应该从文件操作开始。我建议编写一个在给定String 上正常工作的函数。这样,您就可以了解语法、模式匹配、列表操作(映射、折叠)和递归,而不会被 do 表示法分心(这有点看起来是必要的,但不是,并且确实需要更深入的了解)。

您应该查看Learn you a HaskellReal World Haskell 以获得良好的基础。你现在所做的只是在黑暗中跌跌撞撞——如果你学习的语言与你知道的语言相似,这可能行得通,但绝对不适合 Haskell。

【讨论】:

    【解决方案2】:

    我应该首先重复每个人都会(并且应该)说的话:从像 Real World Haskell 这样的书开始!也就是说,我将发布一个可编译代码的快速演练,并希望能做一些接近你最初打算的事情。注释是内联的,希望能说明您的方法的一些缺点。

    import Text.Regex.Posix                                                               
    
    -- Let's start by wrapping your first attempt into a 'Monadic Action'
    -- IO is a monad, and hence we can sequence 'actions' (read as: functions)
    -- together using do-notation.                                                                 
    attemptOne :: IO [[String]]
    -- ^ type declaration of the function 'attemptOne'
    -- read as: function returning value having type 'IO [[String]]'                                                            
    attemptOne = do                                                                        
      putStrLn "type text file"                                                            
      filePath <- getLine                                                                  
      fileData <- readFile filePath                                                        
      putStrLn fileData                                                                    
    
      let parsed = fileData =~ "[^- \".,\n]+" :: [[String]]
      -- ^ this form of let syntax allows us to declare that
      -- 'wherever there is a use of the left-hand-side, we can
      -- substitute it for the right-hand-side and get equivalent
      -- results.                            
      putStrLn ("The data after running the regex: " ++ concatMap concat parsed)           
    
      return parsed                                      
      -- ^ return is a monadic action that 'lifts' a value
      -- into the encapsulating monad (in this case, the 'IO' Monad).                                  
    
    -- Here we show that given a search term (a String), and a body of text to             
    -- search in, we can return the frequency of occurrence of the term within the         
    -- text.                                                                               
    searchingFunc :: String -> [String] -> Int                                             
    searchingFunc term                                                                     
        = length . filter predicate                                                        
      where                                                                                
        predicate = (==)term                                                               
      -- ^ we use function composition (.) to create a new function from two               
      -- existing ones:                                                                    
      --   filter (drop any elements of a list that don't satisfy                          
      --           our predicate)                                                          
      --   length: return the size of the list                                             
    
    -- Here we build a wrapper-function that allows us to run our 'pure'            
    -- searchingFunc on an input of the form returned by 'attemptOne'.                                                                 
    runSearchingFunc :: String -> [[String]] -> [Int]                                      
    runSearchingFunc term parsedData                                                       
      = map (searchingFunc term) parsedData                                                
    
    -- Here's an example of piecing everything together with IO actions                    
    main :: IO ()                                                                          
    main = do                                                                              
      results <- attemptOne                                                                
      -- ^ run our attemptOne function (representing IO actions)                           
      -- and save the result                                                               
      let searchResults = runSearchingFunc "foo" results                                   
      -- ^ us a 'let' binding to state that searchResults is                               
      -- equivalent to running 'runSearchingFunc'                                          
      print searchResults                                                                  
      -- ^ run the IO action that prints searchResults                                     
      print (runSearchingFunc "foo" results)                                               
      -- ^ run the IO action that prints the 'definition'                                  
      -- of 'searchResults'; i.e. the above two IO actions                                 
      -- are equivalent.                                                                   
      return ()
      -- as before, lift a value into the encapsulating Monad;
      -- this time, we're lifting a value corresponding to 'null/void'.
    

    要加载此代码,请将其保存到 .hs 文件中(我将其保存到“temp.hs”中),然后从 ghci 运行以下命令。注意:文件“f”包含几个输入词:

    *Main Text.Regex.Posix> :l temp.hs                               
    [1 of 1] Compiling Main             ( temp.hs, interpreted )     
    Ok, modules loaded: Main.                                        
    *Main Text.Regex.Posix> main                                     
    type text file                                                   
    f                                                                
    foo foos foor fo foo foo                                         
    
    The data after running the regex: foofoosfoorfofoofoo            
    [1,0,0,0,1,1]                                                    
    [1,0,0,0,1,1]                                                    
    

    这里发生了很多事情,从 do 表示法到 Monadic 动作,“let”绑定到纯函数/值和非纯函数/值之间的区别。我不能强调从一本好书学习基础知识的价值!

    【讨论】:

      【解决方案3】:

      这就是我所做的。它不做任何错误检查,并且尽可能基本。

      import Text.Regex.Posix ((=~))
      import Control.Monad (when)
      import Text.Printf (printf)
      
      -- Calculates the number of matching words
      matchWord :: String -> String -> Int
      matchWord file word = length . filter (== word) . concat $ file =~ "[^- \".,\n]+"
      
      getInputFile :: IO String
      getInputFile = do putStrLn "Enter the file to search through:"
                        path <- getLine
                        readFile path -- Attention! No error checking here
      
      repl :: String -> IO ()
      repl file = do putStrLn "Enter word to search for (empty for exit):"
                     word <- getLine
                     when (word /= "") $
                       do print $ matchWord file word
                          repl file
      
      main :: IO ()
      main = do file <- getInputFile
                repl file
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-04
        • 1970-01-01
        • 2012-03-29
        • 1970-01-01
        • 2012-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多