user2831765
user2831765

Reputation: 1

creating a dialogue in command line in haskell, where output depends on previous processed input

I am finishing a program that translates a higher-order language to another and I am having trouble dealing with the interface I am trying to implement.

The idea is that it asks the user for a number to be chosen, then checks whether it is a number, if it is, it follows with a line asking to write the given term to be translated.

If the number is 4, it has an additional line asking for the term to be substituted, thus the translating function takes 2 args instead of 1. Therefore I'd like to have 3 lines of input for the user to complete depending on the previous answer, however my code asks for a number and then prints the next question and returns directly to the beginning, printing the first lines again.

I have noticed that it does not test the validity of the Char taken from the input*(isDigit num)* and always chooses the path of if(ord num /= 4) equals to True, even when I key the number 4!

I have tried several paths to sort this out but I am at a lost. I am more than happy to change my interface code completely if you know of any better approaches, because I cannot think of any other.

I am quite amateur at Haskell by the way.

main :: IO ()
main = do 
        putStrLn  "Choose a definition to be implemented:\n 1 - Def 1 dealing with a Generalised class of CRS terms without permutations,\n 2 - Def 2 which is an extension of Def 1 with permutations,\n 3 - Def 4 which takes a closed nominal term-in-context, returning a closed CRS (meta)term,\n 4 - Def 6 which extends on Def 4 by adding a ground nominal substitution to the arguments.\n Definition number: "
        num <- getChar
        unless (isDigit num)   (return ())
        def num       
        main

def :: Char -> IO String
def num = do
           putStrLn "write a nominal term-in-context: "
           hFlush stdout
           str <- getLine  
           case num of
               '1'   -> (return . readExp1) str
               '2'   -> (return . readExp2) str
               '3'   -> (return . readExp4) str
               '4'   -> do
                         putStrLn "write a nominal term and the variable it substitutes:"              
                         sub <- getLine
                         let term = readExp6 str (readSub sub)
                         return term

{- reads and ouputs type TrmCxt ((atm,Var),Trm)         -}  
readExp1 :: String -> String
readExp1 s = case (inputL parseT s) of
           Left err -> "error: " ++ err
           Right (fc , t) -> show $ translate1 [] fc  t

I have added to the snippet the function readExp1 which parses the input and calls the translating function for you to understand what it does and what it returns. The others are equivalent in their return type.

Upvotes: 0

Views: 264

Answers (3)

Yitz
Yitz

Reputation: 5117

The line def num in your do statement does not produce any output. It just translates the term, discards the resulting String, and goes on to repeat main.

You probably want something like

ans <- def num

    putStrLn ans

instead.

See also another bug that @nponeccop pointed out in a different answer.

Upvotes: 0

user2407038
user2407038

Reputation: 14588

unless (isDigit num) (return ()) does nothing.

From the documentation: "unless : The reverse of when." and "when debug (putStr "Debugging\n") will output the string Debugging\n if the Boolean value debug is True, and otherwise do nothing."

If isDigit num is False, we perform the action return (); otherwise, we 'do nothing', which is defined as being the action return ().

Replacing the following

unless (isDigit num)   (return ())
def num       
main

with

when (isDigit num) $ do
    def num       
    main

will call def num and afterwards continue your loop if isDigit num, otherwise it will immediately exit (I'm not sure if this is what you want to happen).

Upvotes: 0

nponeccop
nponeccop

Reputation: 13677

ord num /= 4 is incorrect. A minimal fix is to use num /= '4' instead.

A better way is to add a case for '4' ->.

You should print the result of def as @Yitz suggests. The error you see is because def num :: IO String. You cannot pass that to putStrLn directly. So you should use either

def num >>= putStrLn

or

df <- def num
putStrLn df

in the do-block in main.

Upvotes: 1

Related Questions