-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GADT type system #23
base: main
Are you sure you want to change the base?
GADT type system #23
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Hello world. This file is written to test the expansions of kb_example.csv. We should see that @@hl is expanded to hello. This is a @@thm, which we cannot @@prf. No @@lmm or @@ax can be used, because this is not a scientific theorem. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Hello world. This file is written to test the expansions of kb_example.csv. We should see that hello is expanded to hello. This is a theorem, which we cannot proof. No lemma or axiom can be used, because this is not a scientific theorem. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,22 +9,40 @@ Stability : experimental | |
|
||
module LibCli.Main where | ||
|
||
import qualified LibCli.Spec as CS (ShortHndr (..), cliModes) | ||
import qualified System.Console.CmdArgs as CMD | ||
import LibCli.Spec | ||
import LibCore.Decoder (decode) | ||
import LibCore.KnowledgeBase (getKnowledgeBase) | ||
import LibCore.Mapper (mapParseStructure) | ||
import LibCore.OutputInterface (returnOutput) | ||
import LibCore.Parser (doParse) | ||
import System.Console.CmdArgs.Explicit | ||
( HelpFormat (HelpFormatAll) | ||
, helpText | ||
, processArgs | ||
) | ||
|
||
----------------------- | ||
-- Command Handlers: -- | ||
----------------------- | ||
|
||
-- TODO(tech-debt): define a typeclass for the modes instead of the pattern matching | ||
-- TODO: (future task) implement the actual handlers with the business logic. | ||
mockCliHandler :: CS.ShortHndr -> IO () | ||
mockCliHandler [email protected]{} = print $ "replacing! --> " ++ show c | ||
mockCliHandler [email protected]{} = print $ "expanding! --> " ++ show c | ||
mockCliHandler [email protected]{} = print $ "listing! --> " ++ show c | ||
mockCliHandler [email protected]{} = print $ "adding! --> " ++ show c | ||
mockCliHandler [email protected]{} = print $ "updating! --> " ++ show c | ||
mockCliHandler [email protected]{} = print $ "deleting! --> " ++ show c | ||
handleExpMode :: Expansion -> IO () | ||
handleExpMode (Re r) = replaceMode r | ||
handleExpMode (Ex c) = print $ "expanding! --> " ++ show c | ||
|
||
handleKbtMode :: KnowledgeBaseTypes -> IO () | ||
handleKbtMode (Lst c) = print $ "listing! --> " ++ show c | ||
handleKbtMode (Ad c) = print $ "adding! --> " ++ show c | ||
handleKbtMode (Up c) = print $ "updating! --> " ++ show c | ||
handleKbtMode (Del c) = print $ "deleting! --> " ++ show c | ||
|
||
replaceMode :: Replace -> IO () | ||
replaceMode c = do | ||
case input c of | ||
Nothing -> error "No input file was found" | ||
Just f -> do | ||
s <- readFile f | ||
returnOutput (out c) (decode $ mapParseStructure getKnowledgeBase $ doParse s) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is cool! Although I am not certain I follow fully why this change to the "Explicit" mode was necessary? 🤔 It's sure possible that I am missing something. Could you make elaborate a bit on the motivation? If you check the comment on #22 (this one), this looks very similar to what I wrote there :))) I'm not sure if one or the other approach is easier/more reliable so please let's check this out? :)) |
||
|
||
---------------------------- | ||
-- Executable entrypoiny: -- | ||
|
@@ -50,4 +68,9 @@ mockCliHandler [email protected]{} = print $ "deleting! --> " ++ show c | |
-- | ||
-- * See 'LibCli.Spec' for more information about the CLI endpoints. | ||
cliMain :: IO () | ||
cliMain = mockCliHandler =<< CMD.cmdArgs (CMD.modes CS.cliModes) | ||
cliMain = do | ||
xs <- processArgs arguments | ||
case xs of | ||
Exp ex -> handleExpMode ex | ||
Kbt kbt -> handleKbtMode kbt | ||
Hlp -> print $ helpText [] HelpFormatAll arguments | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool! This is really fun to see the explicit mode, I like it, but at the same time, it appears a bit more verbose, which is both a good thing (more explicit), but also I am not sure if this makes it more complicated to maintain in the future. I'm all pro going with this approach if there's a clear advantage! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only advantage is that we can define our custom handlers, but I dislike the verbosity and maintenance it will cause |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{-# LANGUAGE DeriveDataTypeable #-} | ||
{-# LANGUAGE GADTs #-} | ||
|
||
{-| | ||
Description : Command Line Interface - Specification | ||
|
@@ -8,131 +8,191 @@ Maintainer : [email protected]; [email protected]; w.j.zwietering | |
Stability : experimental | ||
-} | ||
|
||
module LibCli.Spec | ||
( cliModes | ||
, ShortHndr(..) | ||
) where | ||
module LibCli.Spec where | ||
|
||
import qualified System.Console.CmdArgs as CMD | ||
import System.Console.CmdArgs.Explicit | ||
( Mode | ||
, flagArg | ||
, flagHelpSimple | ||
, flagNone | ||
, flagReq | ||
, mode | ||
, modes | ||
) | ||
|
||
----------------------------------- | ||
-- CLI interface specificaitons: -- | ||
----------------------------------- | ||
|
||
data Expansion where | ||
Re :: Replace -> Expansion | ||
Ex :: Expand -> Expansion | ||
deriving (Show) | ||
|
||
data KnowledgeBaseTypes where | ||
Lst :: List -> KnowledgeBaseTypes | ||
Ad :: Add -> KnowledgeBaseTypes | ||
Up :: Update -> KnowledgeBaseTypes | ||
Del :: Delete -> KnowledgeBaseTypes | ||
deriving (Show) | ||
|
||
data ShortHndrModes where | ||
Exp :: Expansion -> ShortHndrModes | ||
Kbt :: KnowledgeBaseTypes -> ShortHndrModes | ||
Hlp :: ShortHndrModes | ||
deriving (Show) | ||
|
||
|
||
-- |ShortHndr CLI interface specification. | ||
data ShortHndr | ||
-- |Defines the arguments for the replace command | ||
-- |Defines the arguments for the replace command | ||
data Replace | ||
= Replace | ||
{ input :: Maybe FilePath | ||
, out :: Maybe FilePath | ||
, inplace :: Maybe Bool | ||
, kb :: Maybe FilePath | ||
{ input :: Maybe FilePath | ||
, out :: Maybe FilePath | ||
, inplace :: Maybe Bool | ||
, replace_kb :: Maybe FilePath | ||
} | ||
-- |Defines the arguments for the expand command | ||
| Expand | ||
{ abbreviation :: String | ||
, kb :: Maybe FilePath | ||
} | ||
-- |Defines the arguments for the list command | ||
| List | ||
{ kb :: Maybe FilePath | ||
deriving (Show) | ||
|
||
-- |Defines the arguments for the expand command | ||
data Expand | ||
= Expand | ||
{ expand_abbr :: String | ||
, expand_kb :: Maybe FilePath | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we add prefixes to the record attributes in these cases? I think they don't overlap with other records in any case, so this shouldn't be a problem IIRC? I might be missing something ofc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a name clash error. I don't recall the exact one |
||
} | ||
-- |Defines the arguments for the add command | ||
| Add | ||
{ abbreviation :: String | ||
, expansion :: String | ||
, kb :: Maybe FilePath | ||
deriving (Show) | ||
|
||
-- |Defines the arguments for the list command | ||
newtype List | ||
= List { list_kb :: Maybe FilePath } | ||
deriving (Show) | ||
|
||
-- |Defines the arguments for the add command | ||
data Add | ||
= Add | ||
{ add_abbr :: String | ||
, add_expansion :: String | ||
, add_kb :: Maybe FilePath | ||
} | ||
-- |Defines the arguments for the update command | ||
| Update | ||
{ abbreviation :: String | ||
, expansion :: String | ||
, kb :: Maybe FilePath | ||
deriving (Show) | ||
|
||
-- |Defines the arguments for the update command | ||
data Update | ||
= Update | ||
{ update_abbr :: String | ||
, update_expansion :: String | ||
, update_kb :: Maybe FilePath | ||
} | ||
-- |Defines the arguments for the delete command | ||
| Delete | ||
{ abbreviation :: String | ||
, kb :: Maybe FilePath | ||
deriving (Show) | ||
|
||
-- |Defines the arguments for the delete command | ||
data Delete | ||
= Delete | ||
{ delete_abbr :: String | ||
, delete_kb :: Maybe FilePath | ||
} | ||
deriving (CMD.Data, CMD.Typeable, Show) | ||
|
||
-- |Utility function to provide help for the file type arguments. | ||
fileFlags :: String -> Maybe FilePath -> Maybe FilePath | ||
fileFlags h f = f CMD.&= CMD.help h CMD.&= CMD.typFile | ||
|
||
------------------------- | ||
-- Expansion commands: -- | ||
------------------------- | ||
|
||
replace :: ShortHndr | ||
replace = | ||
Replace | ||
{ input = fileFlags "Source file" (pure "shorthndr-input.txt") | ||
, out = fileFlags "Output file" (pure "shorthndr--out.txt") | ||
, kb = fileFlags "Knowledge Base source file" | ||
(pure "shorthndr-kb.csv") | ||
, inplace = CMD.def | ||
} | ||
CMD.&= CMD.help | ||
"Replace all abreviations in the provided file with their expansions" | ||
|
||
expand :: ShortHndr | ||
expand = | ||
Expand | ||
{ abbreviation = CMD.def | ||
, kb = fileFlags "Knowledge Base source file" | ||
(pure "shorthndr-kb.csv") | ||
} | ||
CMD.&= CMD.help | ||
"Expand a provided abbreviation abbreviation if one is found" | ||
|
||
expansionModes :: [ShortHndr] | ||
expansionModes = [replace, expand] | ||
|
||
------------------------------ | ||
-- Knowledge Base commands: -- | ||
------------------------------ | ||
|
||
list :: ShortHndr | ||
list = | ||
List { kb = fileFlags "Knowledge Base source file" (pure "shorthndr-kb.csv") | ||
} | ||
CMD.&= CMD.help "List all records of the Knowledge Base" | ||
|
||
add :: ShortHndr | ||
add = | ||
Add { abbreviation = CMD.def | ||
, expansion = CMD.def | ||
, kb = fileFlags "Knowledge Base source file" (pure "shorthndr-kb.csv") | ||
} | ||
CMD.&= CMD.help "Add a new abbreviation record to the Knowledge Base" | ||
|
||
update :: ShortHndr | ||
update = | ||
Update | ||
{ abbreviation = CMD.def | ||
, expansion = CMD.def | ||
, kb = fileFlags "Knowledge Base source file" | ||
(pure "shorthndr-kb.csv") | ||
} | ||
CMD.&= CMD.help | ||
"Update an existing abbreviation record in the Knowledge Base" | ||
|
||
delete :: ShortHndr | ||
delete = | ||
Delete | ||
{ abbreviation = CMD.def | ||
, kb = fileFlags "Knowledge Base source file" | ||
(pure "shorthndr-kb.csv") | ||
} | ||
CMD.&= CMD.help "Delete an abbreviation record from the Knowledge Base" | ||
|
||
kbModes :: [ShortHndr] | ||
kbModes = [list, add, update, delete] | ||
deriving (Show) | ||
|
||
|
||
----------------------------- | ||
-- All exported CLI modes: -- | ||
----------------------------- | ||
|
||
cliModes :: [ShortHndr] | ||
cliModes = expansionModes ++ kbModes | ||
defaultMode :: ShortHndrModes | ||
defaultMode = Hlp | ||
|
||
helpMode :: ShortHndrModes -> ShortHndrModes | ||
helpMode _ = Hlp | ||
|
||
-- Explicit arguments | ||
arguments :: Mode ShortHndrModes | ||
arguments = modes "ShortHandr" defaultMode "Use 'replace' to enter replace mode" [replaceArgs, expandArgs, listArgs, addArgs, updateArgs, deleteArgs] | ||
|
||
replaceArgs :: Mode ShortHndrModes | ||
replaceArgs = mode "replace" initial | ||
"Replace all abreviations in the provided file with their expansions" | ||
(flagArg (updateMode "") "replace") | ||
[ | ||
flagReq ["input", "i"] (updateMode "input") "FILENAME" "Input filename" | ||
,flagReq ["out", "o"] (updateMode "out") "FILENAME" "Output filename" | ||
,flagReq ["k"] (updateMode "replace_kb") "FILENAME" "Knowledgebase filename" | ||
,flagNone ["inplace"] (setInplace True) "inplace" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Exp $ Re $ Replace { input = Just "", out = Just "", replace_kb = Just "", inplace = Just False } | ||
|
||
setInplace :: Bool -> ShortHndrModes -> ShortHndrModes | ||
setInplace b (Exp (Re r)) = Exp $ Re $ r {inplace = Just b} | ||
setInplace _ r = r | ||
|
||
expandArgs :: Mode ShortHndrModes | ||
expandArgs = mode "expand" initial | ||
"Expand a provided abbreviation abbreviation if one is found" | ||
(flagArg (updateMode "abbr") "abbreviation") | ||
[ | ||
flagReq ["k"] (updateMode "expand_kb") "FILENAME" "Knowledgebase filename" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Exp $ Ex $ Expand { expand_abbr = "", expand_kb = Just "" } | ||
|
||
listArgs :: Mode ShortHndrModes | ||
listArgs = mode "list" initial | ||
"List all records of the Knowledge Base" | ||
(flagArg (updateMode "") "list") | ||
[ | ||
flagReq ["k"] (updateMode "list_kb") "FILENAME" "Knowledgebase filename" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Kbt $ Lst $ List { list_kb = Just "" } | ||
|
||
addArgs :: Mode ShortHndrModes | ||
addArgs = mode "add" initial | ||
"Add a new abbreviation record to the Knowledge Base" | ||
(flagArg (updateMode "") "add") | ||
[ | ||
flagReq ["k"] (updateMode "add_kb") "FILENAME" "Knowledgebase filename" | ||
,flagReq ["ex"] (updateMode "add_ex") "expansion" "Abbreviation expansion" | ||
,flagReq ["abbr"] (updateMode "add_abbr") "abbreviation" "Abbreviation" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Kbt $ Ad $ Add { add_abbr = "", add_expansion = "", add_kb = Just "" } | ||
|
||
updateArgs :: Mode ShortHndrModes | ||
updateArgs = mode "update" initial | ||
"Update an existing abbreviation record in the Knowledge Base" | ||
(flagArg (updateMode "") "update") | ||
[ | ||
flagReq ["k"] (updateMode "update_kb") "FILENAME" "Knowledgebase filename" | ||
,flagReq ["ex"] (updateMode "update_ex") "expansion" "Abbreviation expansion" | ||
,flagReq ["abbr"] (updateMode "update_abbr") "abbreviation" "Abbreviation" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Kbt $ Up $ Update { update_abbr = "", update_expansion = "", update_kb = Just "" } | ||
|
||
deleteArgs :: Mode ShortHndrModes | ||
deleteArgs = mode "delete" initial | ||
"Delete an abbreviation record from the Knowledge Base" | ||
(flagArg (updateMode "") "delete") | ||
[ | ||
flagReq ["k"] (updateMode "delete_kb") "FILENAME" "Knowledgebase filename" | ||
,flagReq ["abbr"] (updateMode "delete_abbr") "abbreviation" "Abbreviation" | ||
,flagHelpSimple helpMode | ||
] | ||
where initial = Kbt $ Del $ Delete { delete_abbr = "", delete_kb = Just "" } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow man, this is a lot of work!!!! 👀 Dude, you're a machine, thanks for investing all the time here 🚀 |
||
|
||
updateMode :: String -> String -> ShortHndrModes -> Either String ShortHndrModes | ||
updateMode "input" s (Exp (Re r)) = Right $ Exp $ Re $ r {input = Just s} | ||
updateMode "out" s (Exp (Re r)) = Right $ Exp $ Re $ r {out = Just s} | ||
updateMode "replace_kb" s (Exp (Re r)) = Right $ Exp $ Re $ r {replace_kb = Just s} | ||
updateMode "expand_kb" s (Exp (Ex r)) = Right $ Exp $ Ex $ r { expand_kb = Just s} | ||
updateMode "abbr" s (Exp (Ex r)) = Right $ Exp $ Ex $ r { expand_abbr = s } | ||
updateMode "list_kb" s (Kbt (Lst r)) = Right $ Kbt $ Lst $ r { list_kb = Just s} | ||
updateMode "add_kb" s (Kbt (Ad r)) = Right $ Kbt $ Ad $ r { add_kb = Just s} | ||
updateMode "add_ex" s (Kbt (Ad r)) = Right $ Kbt $ Ad $ r { add_expansion = s} | ||
updateMode "add_abbr" s (Kbt (Ad r)) = Right $ Kbt $ Ad $ r { add_abbr = s} | ||
updateMode "update_kb" s (Kbt (Up r)) = Right $ Kbt $ Up $ r { update_kb = Just s} | ||
updateMode "update_ex" s (Kbt (Up r)) = Right $ Kbt $ Up $ r { update_expansion = s} | ||
updateMode "update_abbr" s (Kbt (Up r)) = Right $ Kbt $ Up $ r { update_abbr = s} | ||
updateMode "delete_kb" s (Kbt (Del r)) = Right $ Kbt $ Del $ r { delete_kb = Just s} | ||
updateMode "delete_abbr" s (Kbt (Del r)) = Right $ Kbt $ Del $ r { delete_abbr = s} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure I can follow fully what this does? 👀 😓 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updateMode is a somewhat magical function that updates records. It uses a magic string and a pattern match to update values. Lenses would be better here, but getting that approach working here took me too much time. |
||
updateMode _ _ e = Right e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a little overlap with #22 PR. So I am not sure if there is a technical dependency between them or is it a continuation of the other? Is it safe to merge both or are they alternatives?