I like the Pattern thing. However, it seems to me that you're going to quickly run into trouble if you need to even vaguely emulate shell scripting. Shell utilities live and die by their options. It's unfortunate Haskell supports neither named arguments nor default values. Which means that in order to emulate options, you would need to pass records to your "shell" utility, which, on top of being cumbersome, forces you to prefix every option in a way unique to your utility, since you cannot have two records with the same fields in the same namespace...
It's going to be difficult for something like this to match the ease of shell scripting. For instance, typing `cd "foo"` is significantly more painful than `cd foo`. (Maybe this could be fixed by forking or adding to ghci so that when you hit space after the function name it automatically puts the quotes in for you and places the cursor between them.) Options are certainly important, and as others have said, they can be emulated with records. Is the syntax going to just as convenient as shell scripting? No. But that's not the point. The point is that shell scripting is massively painful in a lot of other ways where Haskell blows it away. So the task is to find a happy medium that gets fairly close to the convenience of shell scripting while still giving us the power of Haskell.
There are a number of potential approaches for coming close to the ease of shell scripting. One is options records as others have mentioned. For defaults you can have a Default instance (no, that's not boilerplate because you would have had to specify the defaults somewhere anyway). Then there is plenty of room for infix operator combinators to make it easier to change individual options. A second option could be to put options into a string that would get parsed into a record. You could use patterns similar to those used in existing command line argument processors like optparse-applicative. Or, if you don't like that, then maybe a quasiquote could give more power.
Do these things require some boilerplate? Yes. We know that is going to be required since Haskell wasn't designed for the convenience that shells were designed for. But that's fine in this case because the potential benefits are huge.
The issue is that, if you want to simulate both "grep" and "grep -r", you need to different functions, or you need to have your "grep" function accept a record of parameters.
I'm not good enough haskell programmer, but there is possible solution (records as you mentioned).
import Prelude hiding ((-))
data Grep = Grep {isRecursive :: Bool, maxCount :: Maybe Int} --etc
deriving (Show)
grep = Grep False Nothing
--short pseudonim
r :: Grep -> Grep
r command = command{isRecursive = True}
m :: Int -> Grep -> Grep
m num command = command{maxCount = Just num}
(-) :: a -> (a -> a) -> a
(-) command flag = flag command
ourGrep = grep -m 50 -r
main = print ourGrep -- > Grep {isRecursive = True, maxCount = Just 50}
--then we should write monad which execute that data
Yes, that's exactly what I wouldn't want to type. Also, your record is going to blow up in the likely case another utility uses a recursive flag, because of Haskell's pervasive namespacing problems.
in a typesafe way. It just probably wouldn't be worth the complexity. It also probably couldn't be a straight `IO` action then, which was a design constraint of Gabriel's.
Actually, you can do `grep -r` by just combining `grep` and `lstree`. Here's an example:
example = do
file <- lstree "some/dir"
True <- liftIO (testfile file)
grep "Some pattern" (input file)
This is an example of how most of Bash's option heavy ecosystem is an outgrowth of Bash's limitation as a language (individual commands accumulate flags to work around functionality difficult to implement within the Host language). I think having a decent host language decreases the need for so many configuration knobs for every command.
You're right to some extent, but I think many of these 'knobs' have a good reason to exist (--dry-run, -a, -z for rsync for instance) and cannot be usefully, or at all, replaced by more composability. And attempting to implement support for them will run against the limitations of Haskell's syntax.
Something like OCaml would be better suited, since polymorphic variants, named and default arguments give a lot more flexibility, though the fact that shell commands happily return different outputs depending on their options would still be an issue.
I saw those as regular parser that returns text but not just grep wrapper. Yes It has function named 'grep', but its not grep wrapper. It looks like `lstree` could be combined with `grep` function for emulate `grep -r`.
I guess you wouldn't, you'd have a sort function afterwards.
...for Unix' insistence on composability, the shell tools are often unnecessarily monolithic, probably because that's the only sane way if the only type you have in interconnect is `string`.
Sure, but consider the common case of wanting the most recent file/directory in a directory. This would be something like "ls -t|head -n 1". It's pretty convenient, AND your ls function still returns only file and directory names, no additional information.
Here, you'd need to either parametrize the return type of ls to get simple strings (which is what you want most of time) or additional metadata, or alternatively to have different ls commands.
There have been probably 15 different proposals for this throughout the years. They never make enough momentum to go through. While record pain points seem like a huge deal, in practice they're not sufficiently bad to motivate changes in the language in the face of the various tradeoffs that would have to be made.
Today, typeclasses and lenses cover 99% of "the record problem" as far as I've experienced.
First, it doesn't let you install multiple packages in one go (or let you install a specific package version). Secondly, it doesn't support apt-get options like -m, -d -n...
You could extend your argument structure for this, but then you need to specify every argument all the time, or have the user modify a default value. This is definitely awkward compared to straight shell.