In Haskell, as a user adds an item to a list

I understand how to use recursive data structures to manage a list of items:

data Thingy a = NoThingy | Thingy aa (Thingy a) deriving (Show, Read) firstThingsFirst :: a -> a -> (Thingy a) firstThingsFirst ab = Thingy ab NoThingy andAnotherThing :: a -> a -> Thingy a -> Thingy a andAnotherThing ab NoThingy = Thingy ab NoThingy andAnotherThing ab things = Thingy ab things 

And in ghci I can do something like:

 let x=andAnotherThing "thing1" "thing2" NoThingy let y=andAnotherThing "thing3" "thing4" x 

However, I do not know how to make this work for a compiled program that accepts user input. In other words, I want the user to populate the structure. Sort of:

 import System.IO allThings=NoThingy main = do putStrLn "First Thing" first<-getLine putStrLn "Second Thing" second<-getLine let allThings=Thingy first second allThings print allThings main 
+4
source share
4 answers

The values ​​in Haskell are immutable, so if you β€œadd an item to the list”, you get a new list. Therefore in your code above

 let allThings = Thingy first second allThings 

Don't do what you expect. The top level of allThings is NoThingy , and this cannot change. The name allThings in let-binding does not apply to the top-level entity, it introduces a new binding that obscures the top-level name, and that the new name is also mentioned on the right side of the binding. So the string and the following equivalents

 let theThings = Thingy first second theThings print theThings 

The let binding creates a circular structure, referring to itself as one of its components. This means that, of course, printing will never end.

What you (probably) want to accomplish requires passing the structure you want to update as a parameter

 loop things = do putStrLn "First Thing" ... let newThings = Thingy first second things print newThings loop newThings 

And of course, as Nicholas said, you probably want to convert the input strings to values ​​of the appropriate type.

+11
source

What you create is the infinitely self-referential "allThings" that prints.

You get attached to the name allThings twice. The first time before the main and the second time before printing.

The second binding refers to allThings at the end of the right side. This link does NOT apply to the first binding. This link is about the second binding.

If you change the name of the second binding and print:

 main = do putStrLn "First Thing" first <- getLine putStrLn "Second Thing" second <- getLine let allThings2 = Thingy (read first) (read second) allThings print allThings2 main 

then you will get a single Thingy printed on each main loop. Since you want to accumulate responses, you can define a tail recursive "query" as follows:

 query old = do putStrLn "First Thing" first<-getLine putStrLn "Second Thing" second<-getLine let new=Thingy first second old print new query new main = query NoThingy 

The above can do what you are looking for.

+2
source

It looks like you're asking for a way to convert from user input of type String to a value of type Thingy . Since your Thingy type already has an instance for Read , you can use the Read function:

 read :: Read a => String -> a 

This makes your main function more like:

 main = do putStrLn "First Thing" first <- getLine putStrLn "Second Thing" second <- getLine let allThings = Thingy (read first) (read second) allThings print allThings main 

Of course, if you enter a string that does not match Thingy, then you get an error message, so you can use readMay from a secure package :

 readMay :: Read a => String -> Maybe a 

Another problem is that type inference cannot guess which type of a intended, so you will also have to give it a hint, possibly having something like:

 let allThings = Thingy (read first :: Int) (read second :: String) allThings 

It may be worth noting that in this definition, allThings is an infinite structure and will forever print: the last call to main will never be reached.

+1
source

The problem is that you are trying to use a variable to store a mutable state (as would be done in an imperative language), but you cannot do this in Haskell. All states must be explicitly passed as arguments to your functions . As pointed out in other answers, allThings is actually a separate variable from allThings in the global scope (it just smooths the same name)

The following example shows how to create a program that forever loops over a list of numbers. I think this is what you want to do and it should not be difficult to adapt it to the "Thingies"

In our case, we must save the state for our cycle - the index of the next number to be entered (1st, 2nd, etc.), and a list of numbers that we have already read. Thus, our loop function will receive this state as an argument and return an IO action.

 module Main where -- Explicit signature so readLn and show don't complain... loop_step :: (Int, [Int]) -> IO () loop_step (i,xs) = do putStrLn ("Enter the " ++ show i ++ "th number:") n <- readLn let newList = n : xs print newList loop_step (i+1, newList) main :: IO () main = do loop_step (1, []) 
+1
source

Source: https://habr.com/ru/post/1381323/


All Articles