Printing two arguments - haskell

I am trying to :load file "hello.hs" and keep getting the errors below.
I am using WinGHCi 1.0.6.
I have printed just one argument and it worked but when I try to print two arguments I get a Not in scope error as shown below.
My hello.hs code contains the code below.
-----------------hello.hs--------------------
module Main where
import System.Environment
main :: IO ( )
main = do
args <- getArgs --Getting first arg
putStrLn("Hello," ++args!!0)
do args1 <- getArgs putStrLn("Hello," ++args1!!1) --Getting second arg
----------Errors while trying to do :load command --------
hello.hs:6:37: Not in scope: ‘args’
hello.hs:7:13:
The last statement in a 'do' block must be an expression
args1 <- getArgs putStrLn ("Hello," ++ args1 !! 1)
hello.hs:7:50:
Not in scope: ‘args1’
Perhaps you meant ‘args’ (line 5)

Put the putStrLn command on a separate line. The second do is not necessary (in fact, it is necessary not to have it). Additionally, you should know that the compiler views hard tabs as padding out to the next eight-space boundary; so although things look correctly indented here on SO, your code's mixture of tabs and spaces is incorrect. I recommend either using a single tab at the beginning of each line in the do block or converting all tabs to spaces. See also my diatribe on tab styles. So:
main = do
args <- getArgs --Getting first arg
putStrLn("Hello," ++args!!0)
args1 <- getArgs
putStrLn("Hello," ++args1!!1) --Getting second arg
This is the smallest change needed to make things work. Additionally, since I see no reason to believe the arguments will change between the two calls to getArgs, you may as well omit the second call and simply reuse args:
main = do
args <- getArgs
putStrLn("Hello," ++args!!0)
putStrLn("Hello," ++args!!1)

Related

Reading line by line in Haskell

I'm trying to read from standard input line by line, and process each line with the function of the type foo :: String -> Int. Is there any way to do that provided that we don't know the number of lines we want to read OR given that the number of lines is provided on the first line?
What I've tried
A lot of things that give meaningless errors, such as "parser error".
For example
main = do {
getLine <- getContents;
let result = show (foo getLine);
putStrLn (foo result);
}
Edit
Strange, but this does not print the length of a
main = do {
a <- getContents;
putStrLn (show (length a));
}
but, this does print 5.
main = do {
a <- getContents;
putStrLn (show 5);
}
The main example of doing that will look as this:
main = do
line <- getLine
yourfunction line
main
this will take lines forever and process them with your function, in case you want it to stop sometime, just check for a command for example:
main = do
line <- getLine
let res = yourfunction line
if res == "Exit" then IO () else main
You may use the function lines to convert the String into [String]. Afterwards map your foo over this list of lines.
Regarding the edit: Your program printing the length works for me. Try either inputting a file or - if entering input interactively - terminating it correctly (via Ctrl-d).
Sidenote: curly brackets and semicolons are rarely seen usually. But this is just style.

Get args Haskell

I'm having problems with an exercise, and can not understand the error.
It should be a simple exercise with args:
import System.IO
import System.Environment
main= do
args < - getArgs
nomeficheiro <- return( args !! 0)
putStrnLn ( "Name is" ++ nomeficheiro)
Then i should run it, with : $ ./comando James
The error:
<interactive>:51:1:
parse error on input ‘$’
Perhaps you intended to use TemplateHaskell
I've read other doubts about args at this fórum and I didn't find any answer that could help me
$ ./comando James isn't meant to be run on GHCi. Instead, $ at the start of the line indicates that the following line should be run in your bash/cmd/shell, not in GHCi:
# in your favourite shell, in the correct directory
./comando James
If you want to run main with arguments within GHCi, you can use :main args:
ghci> :main James
Further remarks
Your current code isn't indented correctly, so make sure that you fix this too. Also, you can use let nomeficheiro = head args instead of … <- return …. Keep in mind that this could lead to problems if one doesn't supply any argument to your program, since head [] calls error.

Flexible number of arguments to haskell program

I am using the System.FilePath.Find module of filemanip to recursively find all files I need to process (here I will be using just printing to console as the action to perform, in order not confuse things). Now, this code:
import System.Environment (getArgs)
import System.FilePath (FilePath)
import System.Directory (doesDirectoryExist, getDirectoryContents,doesFileExist)
import Control.Monad
import System.FilePath.Find (find,always,fileType,(==?),FileType(..),(&&?),extension)
main= do
[dbFile,input]<- getArgs
files <- findFiles input
mapM_ putStrLn files
return ()
searchExtension :: String
searchExtension = ".hs"
findFiles :: FilePath -> IO [String]
findFiles = find (always) ( fileType ==? RegularFile &&? extension ==? searchExtension)
works well with this call
./myprog tet .
In this case, the get argument is ignored (will be the output database file later) and the second argument is searched recursively for matching files. It also allows me to specify just a single file, which is just perfect!
BUT, I would like to be able to specify
./myprog tet path1 path2 path4 file1
but this of course fails in the pattern matching:
./myprog tet . .
myprogt: user error (Pattern match failure in do expression at myprog.hs:11:9-22)
Now, how do I make this program more flexible, so that I can take more than two arguments?
Sorry for asking this, actually, but my Haskell knowledge is limited but increasing for every new thing I have to do in my first project.
Well, you can use a different pattern like:
(dbFile:inputs) <- getArgs
where dbFile will match the first argument passed while inputs will match any number of file names (even 0. If you want at least one path name use inputs#(_:_) instead of the simple inputs).
Then you can use mapM to call findFiles for each path in inputs:
files <- mapM findFiles input
mapM_ putStrLn $ concat files
Instead of mapM you could modify findFiles to accept a [FilePath] argument instead of a simple FilePath.
Note that to parse command arguments you could consider using some module like getopt. You should also read this page about argument handling.

Adding the possibility to write a AST-file to my (rail-)compiler

I'm writing rail-compiler (rail is an esoteric language) in Haskell and I get some problems within the main-function of my mainmodule.
1) I want my program to ask wheter I want to run the compiling-pipeline or simply stop after the lexer and write the AST to a file so another compiler can deal with my AST (Abstract Synatx Tree). Here is my program:
module Main (
main -- main function to run the program
)
where
-- imports --
import InterfaceDT as IDT
import qualified Testing as Test
import qualified Preprocessor as PreProc
import qualified Lexer
import qualified SyntacticalAnalysis as SynAna
import qualified SemanticalAnalysis as SemAna
import qualified IntermediateCode as InterCode
import qualified CodeOptimization as CodeOpt
import qualified Backend
-- functions --
main :: IO()
main = do putStr "Enter inputfile (path): "
inputfile <- getLine
input <- readFile inputfile
putStr "Enter outputfile (path): "
outputfile <- getLine
input <- readFile inputfile
putStr "Only create AST (True/False): "
onlyAST <- getLine
when (onlyAST=="True") do putStrLn "Building AST..."
writeFile outputfile ((Lexer.process . PreProc.process) input)
when (onlyAST=="False") do putStrLn ("Compiling "++inputfile++" to "++outputfile)
writeFile outputfile ((Backend.process . CodeOpt.process . InterCode.process . SemAna.process . SynAna.process . Lexer.process . PreProc.process) input)
I get an error in Line 21 (input <- readFile inputfile) caused by the <-. Why?
How should I do it?
2) Next thing is that I want to refactor the program in that way, that I can call it from the terminal with parameters like runhaskell Main(AST) (in that way it should just create the AST) or like runhaskell Main.hs (in that way it should do the whole pipeline).
I hope for your help!
For your error in (1), your program doesn't look syntactically incorrect at line 21 to me. However an error at <- would happen if that line were indented differently from the previous one. I suspect that you are having an indentation error due to mixing tabs and spaces in a way that looks correct in your editor but disagrees with Haskell's interpretation of tabs. The simplest recommendation is to always use spaces and never tabs.
You also have an extra copy of that line later, which you might want to remove.
I also suspect you may need to use hFlush stdin after your putStr's, for them to work as prompts.
For (2), I'd suggest using a library for proper command line argument and option parsing, such as System.Console.GetOpt which is included with GHC, or one of the fancier ones which you can find on Hackage.

I taught ghci to compile my StackOverflow posts. Can I make it slicker?

Haskell Stack Overflow layout preprocessor
module StackOverflow where -- yes, the source of this post compiles as is
Skip down to What to do to get it working if you want to play with this first (1/2 way down).
Skip down to What I would like if I witter on a bit and you just want to find out what help I'm seeking.
TLDR Question summary:
Can I get ghci to add filename completion to the :so command I defined in my ghci.conf?
Could I somehow define a ghci command that returns code for compilation instead of returning a ghci command, or
does ghci instead have a better way for me to plug in Haskell code as a
file-extension-specific pre-processor, so :l would work for .hs and .lhs files as usual, but use my handwritten preprocessor for .so files?
Background:
Haskell supports literate programming in .lhs source files, two ways:
LaTeX style \begin{code} and \end{code}.
Bird tracks: Code starts with > , anything else is a comment.
There must be a blank line between code and comments (to stop trivial accidental misuse of >).
Don't Bird tracks rules sound similar to StackOverflow's code blocks?
References: 1. The .ghci manual
2. GHCi haskellwiki
3. Neil Mitchell blogs about :{ and :} in .ghci
The preprocessor
I like writing SO answers in a text editor, and I like to make a post that consists of code that works,
but end up with comment blocks or >s that I have to edit out before posting, which is less fun.
So, I wrote myself a pre-processor.
If I've pasted some ghci stuff in as a code block, it usually starts with * or :.
If the line is completely blank, I don't want it treated as code, because otherwise
I get accidental code-next-to-comment-line errors because I can't see the 4 spaces I accidentally
left on an otherwise blank line.
If the preceeding line was not code, this line shouldn't be either, so we can cope with StackOverflow's
use of indentation for text layout purposes outside code blocks.
At first we don't know (I don't know) whether this line is code or text:
dunnoNow :: [String] -> [String]
dunnoNow [] = []
dunnoNow (line:lines)
| all (==' ') line = line:dunnoNow lines -- next line could be either
| otherwise = let (first4,therest) = splitAt 4 line in
if first4 /=" " --
|| null therest -- so the next line won't ever crash
|| head therest `elem` "*:" -- special chars that don't start lines of code.
then line:knowNow False lines -- this isn't code, so the next line isn't either
else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too
but if we know, we should keep in the same mode until we hit a blank line:
knowNow :: Bool -> [String] -> [String]
knowNow _ [] = []
knowNow itsCode (line:lines)
| all (==' ') line = line:dunnoNow lines
| otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
Getting ghci to use the preprocessor
Now we can take a module name, preprocess that file, and tell ghci to load it:
loadso :: String -> IO String
loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- so2bird each line
>>= writeFile (fn++"_so.lhs") -- write to a new file
>> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")
I've used silently redefining the :rso command becuase my previous attemts to use
let currentStackOverflowFile = .... or currentStackOverflowFile <- return ...
didn't get me anywhere.
What to do to get it working
Now I need to put it in my ghci.conf file, i.e. in appdata/ghc/ghci.conf
as per the instructions
:{
let dunnoNow [] = []
dunnoNow (line:lines)
| all (==' ') line = line:dunnoNow lines -- next line could be either
| otherwise = let (first4,therest) = splitAt 4 line in
if first4 /=" " --
|| null therest -- so the next line won't ever crash
|| head therest `elem` "*:" -- special chars that don't start lines of code.
then line:knowNow False lines -- this isn't code, so the next line isn't either
else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too
knowNow _ [] = []
knowNow itsCode (line:lines)
| all (==' ') line = line:dunnoNow lines
| otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- convert each line
>>= writeFile (fn++"_so.lhs") -- write to a new file
>> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")
:}
:def so loadso
Usage
Now I can save this entire post in LiterateSo.so and do lovely things in ghci like
*Prelude> :so StackOverflow
[1 of 1] Compiling StackOverflow ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.
*StackOverflow> :rso
[1 of 1] Compiling StackOverflow ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.
*StackOverflow>
Hooray!
What I would like:
I would prefer to enable ghci to support this more directly. It would be nice to get rid of the intermediate .lhs file.
Also, it seems ghci does filename completion starting at the shortest substring of :load that determines
you're actually doing load, so using :lso instead of :so doesn't fool it.
(I would not like to rewrite my code in C. I also would not like to recompile ghci from source.)
TLDR Question reminder:
Can I get ghci to add filename completion to the :so command I defined in my ghci.conf?
Could I somehow define a ghci command that returns code for compilation instead of returning a ghci command, or
does ghci instead have a better way for me to plug in Haskell code as a
file-extension-specific pre-processor, so :l would work for .hs and .lhs files as usual, but use my handwritten preprocessor for .so files?
I would try to make a standalone preprocessor that runs SO preprocessing code or the standard literary preprocessor, depending on file extension. Then just use :set -pgmL SO-preprocessor in ghci.conf.
For the standard literary preprocessor, run the unlit program, or use Distribution.Simple.PreProcess.Unlit.
This way, :load and filename completion just work normally.
GHCI passes 4 arguments to the preprocessor, in order: -h, the label, the source file name, and the destination file name. The preprocessor should read the source and write to the destination. The label is used to output #line pragmas. You can ignore it if you don't alter the line count of the source (i.e. replace "comment" lines with -- comments or blank lines).

Resources