2010-04-22 33 views
1

我是Haskell的新手,我想提一些關於改進腳本的意見。這是一個代碼生成器,需要一個命令行參數來生成sql腳本。改進haskell腳本

./GenCode "people name:string age:integer" 

代碼:

import Data.List 
import System.Environment (getArgs) 

create_table :: String -> String 

create_table str = "CREATE TABLE " ++ h (words str) 
     where h (x:xs) = let cab = x 
          final = xs 
         in x ++ "(" ++ create_fields xs ++ ")" 

create_fields (x:xs) = takeWhile (/=':') x ++ type x ++ sig 
       where sig | length xs > 0 = "," ++ create_fields xs 
         | otherwise  = " " ++ create_fields xs 
create_fields []  = "" 

type x | isInfixOf "string" x = " CHARACTER VARYING" 
     | isInfixOf "integer" x = " INTEGER" 
     | isInfixOf "date" x = " DATE" 
     | isInfixOf "serial" x = " SERIAL" 
     | otherwise    = "" 

main = mainWith 
    where mainWith = do 
     args <- getArgs 
    case args of 
     [] -> putStrLn $ "You need one argument" 
     (x:xs) -> putStrLn $ (create_table x) 
+3

'_'時

break (==':') "name:string" == ("name", ":string") 

然後通常用於忽略的參數,而且也沒有必要使用'F $ g'和'f(g)'('$'的優先級低於函數應用),例如'(x:_) - > putStrLn $ create_table x'。 – kennytm 2010-04-22 20:38:06

+6

在這裏你會從hlint得到很多建議。它非常好,請查看:http://community.haskell.org/~ndm/hlint/ – jberryman 2010-04-23 02:05:12

+0

'type'對Haskell函數來說不是一個好名字,因爲它是一個保留字。使用例如而不是'type_'。另外,爲所有頂級函數輸入簽名。 'case args ...'需要縮進以與上面的'args'對齊。 – Mohan 2012-12-17 04:10:18

回答

6

我想你知道如何寫已經功能代碼。這裏有一些小的風格說明:

  • 哈斯克爾通常採用駝峯,不under_score_separation
  • create_tablecabofinal不被使用。
  • 通常,像create_fields這樣的列表遞歸函數首先將空列表大小寫。
  • 無論如何,我不會讓create_fields遞歸。逗號加入代碼非常複雜,應該與打字代碼分開。而應該像Data.List.intercalate "," (map create_field xs)那樣做。然後create_field x可以只是takeWhile (/=':') x ++ type x
  • 尤其是如果有很多類型的翻譯,你可以把它們放入一個地圖

像這樣:

types = Data.Map.fromList [("string", "CHARACTER VARYING") 
          ,("integer", "INTEGER") 
          -- etc 
          ] 

然後type可以Data.Maybe.fromMaybe "" (Data.Map.lookup x types)

  • 代碼可以以任何順序出現,所以很高興有main up 面前。 (雖然這是個人偏好)
  • 你不需要mainWith。

只是說

main = do 
    args <- getArgs 
    case args of 
    [] -> ... 
  • 你並不需要美元用於調用putStrLn。在第一次調用中,參數無論如何都不需要括號,而在第二次調用中,您提供括號。或者,您可以保留第二個美元並放棄括號。
+0

我不認爲用於haskell庫函數的camelCase風格與個人代碼的風格指南相關,除非該代碼將要發佈。否則,好點。 – 2010-04-26 10:06:10

5

請勿使用length xs > 0(在sig);當你真正想知道的是它是否爲空時,它不必要地計算了xs的長度。使用null xs檢查非空列表:

... 
where sig | null xs = ... -- Empty case 
      | otherwise = ... -- Non-empty case 

或添加參數sig和模式匹配:

... 
where sig (y:ys) = ... 
     sig []  = ... 

雖然彌敦道桑德斯的建議與intercalate更換整個遞歸的是優秀的並使其成爲一個有爭議的問題。


你也通過傳遞整個"var:type"串入type識別的類型,所以,它正在測試

"string" `isInfixOf` "name:string" 

你可以使用breakspan代替takeWhile到早先分開名稱和類型:

create_fields (x:xs) = xname ++ type xtype ++ sig 
    where 
     (xname, _:xtype) = break (==':') x 
     sig = ... 

然後type可以比較字符串是否相等,或者使用Map查找值。

在使用的break簡單的解釋:結合

(xname, _:xtype) to ("name", ":string"), 

xname -> "name" 
_  -> ':'  (discarded) 
xtype -> "string"