改进haskell脚本

Wer*_*ria 1 haskell coding-style

我是Haskell的新手,我想要一些关于改进这个脚本的意见.这是一个代码生成器,需要一个命令行参数来生成sql脚本.

./GenCode "people name:string age:integer"
Run Code Online (Sandbox Code Playgroud)

码:

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)
Run Code Online (Sandbox Code Playgroud)

Nat*_*ers 6

我想你已经了解了如何编写功能代码.这是一些小风格的笔记:

  • Haskell通常使用camelCase,而不是under_score_separation
  • create_table,cabo并且final不被使用.
  • 通常,像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
                          ]
Run Code Online (Sandbox Code Playgroud)

然后type就可以了Data.Maybe.fromMaybe "" (Data.Map.lookup x types)

  • 代码可以按任何顺序出现,所以最好先预先安排main.(这是个人喜好)
  • 你不需要mainWith.

说啊

main = do
  args <- getArgs
  case args of
    [] -> ...
Run Code Online (Sandbox Code Playgroud)
  • 您不需要美元来拨打电话putStrLn.在第一次调用中,参数不需要括号,在第二次调用中,您提供括号.或者,您可以保留第二个美元并放下括号.


Nef*_*byr 5

不要使用length xs > 0(in sig); 它毫无疑问地计算了xs你真正想知道的时间长度是否为空.使用null xs来检查非空列表:

...
where sig | null xs   = ... -- Empty case
          | otherwise = ... -- Non-empty case
Run Code Online (Sandbox Code Playgroud)

或添加参数sig和模式匹配:

...
where sig (y:ys) = ...
      sig []     = ...
Run Code Online (Sandbox Code Playgroud)

虽然内森桑德斯建议用intercalate一个很好的替代整个递归的东西,但这是一个有争议的问题.


您还要通过传递整个"var:type"字符串来识别类型type,因此它正在测试

"string" `isInfixOf` "name:string"
Run Code Online (Sandbox Code Playgroud)

等等

您可以使用breakspan代替takeWhile以前分隔名称和类型:

create_fields (x:xs) = xname ++ type xtype ++ sig
    where
      (xname, _:xtype) = break (==':') x
      sig = ...
Run Code Online (Sandbox Code Playgroud)

然后type可以比较字符串相等,或使用a查找值Map.

快速解释使用break:

break (==':') "name:string" == ("name", ":string")
Run Code Online (Sandbox Code Playgroud)

然后绑定时

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

 xname -> "name"
 _     -> ':'      (discarded)
 xtype -> "string"
Run Code Online (Sandbox Code Playgroud)