[Haskell-cafe] develop new Haskell shell?
brianh at metamilk.com
Fri May 12 09:48:25 EDT 2006
Donn Cave wrote:
> On Thu, 11 May 2006, Brian Hulley wrote:
>> -- catenate all files in a specified directory
>> catenate outputFile dir = withDir dir $
>> ls >>= cat outputFile
> So, you would apply this like
> catenate "result" "/etc/stuff" ? String literals need quotes?
Yes - why not? Also, on Windows for example, filenames can have spaces so
quotes are needed anyway with any shell at the moment if such filenames are
used. However if this was a real problem it *might* be possible to relax the
need for quotes by using a much more complicated parsing algorithm that
could take into account the types of expected args and coerce the
appropriate unquoted lexemes/expressions into strings, but I don't know if
this would really be worth the trouble, and it would introduce ambiguity eg
is etc/stuff a filename or an arithmetic expression?
>> Of course the above could no doubt be improved but surely it is
>> already far easier to understand and much more powerful than the
>> idiosyncratic text
>> based approach used in UNIX shells (including rc).
> (cd /etc/stuff; cat * > result)
Well the problem here is that the command leaves you in /etc/stuff so you
have to remember this when you subsequently execute another command. The
advantage of withDir is that the original directory is restored afterwards,
which might make it easier to write modular scripts.
In any case you could also make a cd command in Haskell, and write:
cd "etc/stuff" >> ls >>= cat "result"
>> renif extFrom extTo fileName =
>> case split fileName of
>> (n, ext) | ext == extFrom -> rename fileName (unsplit
>> (n, extTo)) _ -> return ()
>> % ls >>= mapM_ (renif "txt" "hs")
> $ for a in *.txt; do mv $a $(basename $a .txt); done
Well someone had to define the meaning of basename so if we make the
definition of renif similarly built-in the comparison is between
ls >>= mapM_ (renif "txt" "hs")
for a in *.txt; do mv $a $(basename $a .txt); done
So the Haskell command is shorter, easier to read, and more re-usable,
because mapM_ (renif "txt" "hs") can be used anywhere that supplies a list
of files whereas "for a in *.txt" doesn't make the source of the list
explicit. Do they come from the current directory? What if some other list
of files should be used?
> ? Not saying the UNIX shell is a rich and well structured programming
> environment, and maybe FP is a good direction for that problem. But
> don't underestimate it, the principles behind it are sharp, and while
> I think you could expect to win on complex data structures, you can't
> afford to lose on simple commands, because that's where most of the
> action is.
>From the above even the simple commands are easier in Haskell. The only
drawback is the need to put quotes round filenames/paths but imho this
doesn't seem like a major problem compared to the ease with which complex
commands can be built up and the advantage of only having to learn one
> Hm. Not to pick at the details too much, but you know "cat" is
> actually a standard UNIX command, that writes to standard output
> and has no output file parameter? What's up with the new parameter
> in your version - was it not going to be workable the way it was?
I forgot about this. You could define cat in Haskell as:
cat :: [FileName] -> Shell String
and have another command analogous to > to write a string into a file, say
into :: FileName -> String -> Shell ()
Then you could catenate all files in the current directory into a file
called "result" by:
ls >>= cat >>= into "result"
(Same as cat * > result)
So in balance I think that while some UNIX commands may be slightly shorter,
the shortness comes at the expense of the assumptions they have to make
about the kinds of things you want to do eg cat * works well if the only
possible source of files is the current directory, but doesn't work at all
if you want to create a list of files from some other operation (unless you
create a temporary directory with symlinks etc but it easily degenerates
into a very complicated mess compared to Haskell).
More information about the Haskell-Cafe