We have the classic flags in the command line tools, those that enable something (without arguments, e.g --help or --version) and others kind of flags that accept arguments (e.g. --output-dir=/home/ or --input-file="in.a", whatever).
But this time, I would like to implement the following kind of.
$ myprogram --GCC-option="--stdlib 11" --debug
In a general way, the flag is like "--PROGRAM-option=ARGUMENT". Then, I keep from this flag, PROGRAM and ARGUMENT values, they are variables. In the example above, we have PROG=GCC and ARGUMENT=--stdlib 11.
How should can I implement this feature in Haskell? I have some experience parsing options in the classic way.
In a recent project of mine I used an approach based on a 'Data.Tree' of option handling nodes. Of course, I haven't released this code so it's of very limited use, but I think the scheme might be helpful.
data OptHandle = Op { optSat :: String -> Bool
, opBuild :: [String] -> State Env [String]
}
The node fields: check to see if the argument satisfied the node; and incrementally built up an initial program environment based on the the remaining arguments (returning unused arguments to be processed by nodes lower in the tree.)
An option processing tree is then hard coded, such as below.
pgmOptTree :: [Tree OptHandle]
pgmOptTree = [mainHelpT,pgmOptT,dbgT]
mainHelpT :: Tree OptHandle
mainHelpT = Node (Op sat bld) []
where
sat "--help" = True
sat _ = False
bld _ = do
mySetEnvShowHelp
return []
pgmOptT :: Tree OptHandle
pgmOptT = Node (Op sat bld) [dbgT]
where
sat = functionOn . someParse
bld ss = do
let (d,ss') = parsePgmOption ss
mySetEnvPgmOpt d
return ss'
You will also need a function which feeds the command line arguments to the tree, checking satisfiability of each node in a forest, executing the opBuild, and calling subforests. After running the handler in the state monad, you should be returned an initial starting environment which can be used to tell main the functionality you want to call.
The option handler I used was actually a little more complicated than this, as my program communicated with Bash to perform tab completions, and included help for most major options. I found the benefit to the approach was that I could more easily keep in sync three command line concerns: enabling tab completions which could inform users the next available commands; providing help for incomplete commands; and actually running the program for complete commands.
Maintaining a tree like this is nice because you can reuse nodes at different points, and add options that work with the others fairly easily.
Related
When I try to put the output of a shell command into an xmonad prompt as a completion option, i.e. as something that can be chosen via the prompt, I keep running compile errors, no matter what I try.
After initially getting a basic custom prompt to work, the following sanity check:
mkXPrompt TestPrompt config (mkComplFunFromList config ["a", compltest) testFun
compltest = do
output <- "b"
return output
This may not be terribly idiomatic Haskell, but it works as expected, it compiles and "a" as well as "b" are available options in the prompt. But I just can't get compltest to return the output of a shell command.
I have extensively looked at the source of all instances of xmonad prompt I could find in xmonad.contrib, and I have also checked here and on other websites for questions regarding similar issues, found a few and read them thoroughly.
The problem is that in all these cases, people are either doing something FAR more complex than what I'm attempting to do, or something that is simply very different. If I was better at Haskell I could probably adapt something for my needs, but so far I have spend several hours cobbling together functions and going from one compile error (usually type errors) to the next, no matter what I tried.
What I could so far gather is that I cannot "extract" a string out of an IO String for security reasons, and so should use liftIO in some way. I have also understood that some of the magic should happen in a do block, and that for Xmonad, runProcessWithInput is supposed to work somewhat better than readProcess. But practically applying this knowledge is a different matter.
Here is a tiny subset of the mass of functions I have tried so far, using the command "date" as an example (i.e. the output of the date command at the time of invoking the prompt should be a completion option in the prompt):
compltest = do
output <- liftIO $ putStrLn $ runProcessWithInput "date" [] ""
return output
compltest = do
output <- liftIO $ runProcessWithInput "date" [] ""
return output
compltest = io $ (runProcessWithInput "date" [] "" >>= readIO)
I guess bind your key to something like this:
do
output <- runProcessWithInput "date" [] ""
mkXPrompt TestPrompt config (mkComplFunFromList config [output]) testFun
Of course there are more interesting things to do with output than making it a singleton list; if f is your favorite String -> [String] function, then replace [output] with (f output) in the last line.
What is the recommended way of running some Action if part of a file changes?
My use-case is given a file that I know exists (concretely elm-package.json), run a shell command (elm package install --yes) if part of the file changes (the dependencies field).
It seems that the Oracle abstraction exposes comparing a value to the last (via Eq). So I tried a newtype like:
newtype ElmDependencies = ElmDependencies () deriving ...
type instance RuleResult ElmDependencies = String
But now, I get stuck actually using this function of type ElmDependencies -> Action String, since the rule I want to write doesn't actually care what the returned String is, it simply wants to be called if the String changes.
In other words,
action $ do
_ <- askOracle (ElmDependencies ())
cmd_ "elm package install --yes"
at the top-level doesn't work; it will run the action every time.
Your askOracle approach is pretty close, but Shake needs to be able to
identify the "output" of the action, so it can give it a persistent name
between runs, so other steps can depend on it, and use that persistent name to avoid recomputing. One way to do that is to make the action create a stamp file, e.g.:
"packages.stamp" *> \out -> do
_ <- askOracle $ ElmDependencies ()
cmd_ "elm package install --yes"
writeFile' out ""
want ["packages.stamp"]
Separately, an alternative to using Oracle is to have a file
elm-package-dependencies.json which you generate from
elm-package.json, write using writeFileIfChanged (which gives you Eq for files), and depend on that
file in packages.stamp. That way you get Eq on files, and can also
easily debug it or delete the -dependencies.json file to force a rerun.
I decided to dive in functional programming world recently, and a friend told me about Haskell. I started my own researches on the language particularity and soon I got the main concepts. Then, I started working with lists and decided to rewrite some existent functions, just to practice.
I made my version of the reverse function, and called it revert. The function is defined as below:
revert :: [a] -> [a]
revert [] = []
revert a = revert (tail a) ++ [head a]
It works perfectly for me, as you can see in the image:
But then, I decided to make another test, receiving the result of the revert function on the same variable that I passed as a parameter, as you can see below:
It seems to execute the function normally, but when I check the value of x, it looks like it goes into a loop, and I need to interrupt the operation.
If I set the value on another variable, it works perfectly:
let y = revert x
Why does it happen? Is it some concept of functional programming that I am missing? Or some peculiarity with Haskell? I did some googling but was not able to get to an answer
PS: Sorry for the bad english
You're defining
x = revert x
So, substituting on the right, this gives
x = revert (revert x)
And so on. Another example would be
a = a + 1
To find out what a is, we need to evaluate the right hand side of the definition.
a = (a + 1) + 1
a = ((a+1)+1) + 1
And so on.
Bootom line: Haskell's = is very different from = in languages like C#, where it means assignment. In Haskell it means is defined as and this means we can substitute any occurance of an identifier with its definition without changing the meaning of the program. This is called referential transpareny.
I'm new to Nix and I'm trying to understand the hello derivation given in example.
I can understand the syntax and what is supposed to do, however I don't understand
how the initial arguments (and the especially the perl one_ are fed ?
I mean, who is setting the perl argument before calling this derivation.
Does that mean that perl is a dependency of hello ?
Packages are typically written as set of dependencies -> derivation functions, to be assembled later. The arguments you ask about are fed from pkgs/top-level/all-packages.nix, which holds the set of all packages in Nixpkgs.
When you find the hello's line in all-packages.nix, you'll notice it's using callPackage - it's signature is path to Nix expression -> overrides -> derivation. callPackage loads the path, looks at the function it loaded, and for each arguments provides either value from overrides or, if not given, from the huge set in all-packages.nix.
For a nice description of callPackage see http://lethalman.blogspot.com/2014/09/nix-pill-13-callpackage-design-pattern.html - it's a less condensed explanation, showing how you could have invented callPackage yourself :-).
This is something of an extension to this question:
Dispatching to correct function with command line arguments in Haskell
So, as it turns out, I don't have a good solution yet for dispatching "commands" from the command line to other functions. So, I'd like to extend the approach in the question above. It seems cumbersome to have to manually add functions to the table and apply the appropriate transformation function to each function so that it takes a list of the correct size instead of its normal arguments. Instead, I'd like to build a table where I'll add functions and "tag" them with the number of arguments it needs to take from the command line. The "add" procedure, should then take care of composing with the correct "takesXarguments" procedure and adding it to the table.
I'd like to be able to install "packages" of functions into the table, which makes me think I need to be able to keep track of the state of the table, since it will change when packages get installed. Is the Reader Monad or the State Monad what I'm looking for?
No monad necessary. Your tagging idea is on the right track, but that information is encoded probably in a different way than you expected.
I would start with a definition of a command:
type Command = [String] -> IO ()
Then you can make "command maker" functions:
mkCommand1 :: (String -> IO ()) -> Command
mkCommand2 :: (String -> String -> IO ()) -> Command
...
Which serves as the tag. If you don't like the proliferation of functions, you can also make a "command lambda":
arg :: (String -> Command) -> Command
arg f (x:xs) = f x xs
arg f [] = fail "Wrong number of arguments"
So that you can write commands like:
printHelloName :: Command
printHelloName = arg $ \first -> arg $ \last -> do
putStrLn $ "Hello, Mr(s). " ++ last
putStrLn $ "May I call you " ++ first ++ "?"
Of course mkCommand1 etc. can be easily written in terms of arg, for the best of both worlds.
As for packages, Command sufficiently encapsulates choices between multiple subcommands, but they don't compose. One option here is to change Command to:
type Command = [String] -> Maybe (IO ())
Which allows you to compose multiple Commands into a single one by taking the first action that does not return Nothing. Now your packages are just values of type Command as well. (In general with Haskell we are very interested in these compositions -- rather than packages and lists, think about how you can take two of some object to make a composite object)
To save you from the desire you have surely built up: (1) there is no reasonable way to detect the number of arguments a function takes*, and (2) there is no way to make a type depend on a number, so you won't be able to create a mkCommand which takes as its first argument an Int for the number of arguments.
Hope this helped.
In this case, it turns out that there is, but I recommend against it and think it is a bad habit -- when things get more abstract the technique breaks down. But I'm something of a purist; the more duct-tapey Haskellers might disagree with me.