Улучшить скрипт на Haskell - PullRequest
1 голос
/ 22 апреля 2010

Я новичок в Хаскеле, и мне хотелось бы высказать некоторые мнения по поводу улучшения этого сценария Это генератор кода, для создания сценария SQL требуется аргумент командной строки.

./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)

Ответы [ 2 ]

6 голосов
/ 23 апреля 2010

Я думаю, вы понимаете, как писать функциональный код уже. Вот несколько небольших заметок о стиле:

  • Haskell обычно использует camelCase, а не under_score_separation
  • In 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
                          ]

Тогда type может быть Data.Maybe.fromMaybe "" (Data.Map.lookup x types)

  • Код может отображаться в любом порядке, поэтому приятно иметь main впереди. (Хотя это личное предпочтение)
  • Вам не нужно mainWith.

Просто скажи

main = do
  args <- getArgs
  case args of
    [] -> ...
  • Вам не нужен доллар для звонков на putStrLn. В первом вызове аргумент в любом случае не требует скобок, а во втором вы указываете скобки. Кроме того, вы можете оставить второй доллар и убрать скобки.
5 голосов
/ 23 апреля 2010

Не используйте length xs > 0sig);он бесполезно считает длину 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"

и т. Д.

Вы можете использовать break или span вместо takeWhile для разделения имени и ввода ранее:

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

изатем type может сравнивать на равенство строк или искать значения, используя Map.

Краткое объяснение этого использования break:

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

Затем при связывании

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

 xname -> "name"
 _     -> ':'      (discarded)
 xtype -> "string"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...