Converting String to Tuple Haskell - string

I'm trying to create a function for a board game that will read a position on the board as a string and convert to a coordinate that can be used in the program e.g. "D4 => (3,3), "F2" => (5,1)".
So far I have this:
getCoord :: String -> Maybe(Int, Int)
getCoord s =
let alphas = "ABCDEFGH"
coord1 = head(s)
coord2 = tail(s)
in ((elemIndex coord1 alphas)-1, read(head coord2)-1)
I'm still learning about the use of Maybe in Haskell and am encountering the error:
• Couldn't match expected type ‘Maybe (Int, Int)’
with actual type ‘(Maybe Int, Integer)’
• In the expression:
((elemIndex coord1 alphas) - 1, read (head coord2) - 1)
Would appreciate your help on where I might be going wrong.
Thanks!

The problem you're facing is that elemIndex returns a Maybe Int. Since you're also trying to return a Maybe type, the best way to work with this is using a do block to perform operations inside the Maybe monad. This lets you use Maybe values as if they were normal values as long as your output will get wrapped back up in a Maybe. (If you need more information about how monads work, there are plenty of good answers here explaining it, and lots of other great posts across the internet.)
import Text.Read (readMaybe)
import Data.List (elemIndex)
getCoords :: String -> Maybe(Int, Int)
getCoords (coord1:coord2) = do
let alphas = "ABCDEFGH"
row <- elemIndex coord1 alphas
col <- readMaybe coord2
return (row, col - 1)
getCoords _ = Nothing
Note a couple other differences from your original.
The use of readMaybe instead of read. readMaybe is a special version of read that returns a value of type Maybe a. Since we're already working in a Maybe context, it's better to have a no-parse return Nothing than throw an error.
No - 1 on the row. elemIndex already has the behavior you want, i.e. A will return 0, etc.
Pattern match instead of head and tail. This lets you account for the case where the string is empty.
Extra definition to match empty list and return Nothing. The advantage of using a Maybe type is that you can return a value for errors instead of getting a Runtime error. In order to make use of that, we have to make sure we handle all of the cases.

Related

Recursive convert a 3-tuple to a char - Haskell

Given this function, I was wondering how one would approach this problem
convertChar' :: [[(Int, Int, Int)]] -> [[Char]]
I have the following helper functions, not sure if they're needed
toList :: [[(Int, Int, Int)]] -> [(Int, Int, Int)]
toList [(x)] = (x)
convertList :: [(Int, Int, Int)] -> [[(Int, Int, Int)]]
convertList x = [x]
The (Int, Int, Int) will either be (1, 1, 1) or (0, 0, 0)
If the tuple is (1, 1, 1) it will return the █ char.
If the tuple is (0, 0, 0) it will return " "
I was wondering what the smart way to approach this is.
Would I have to convert the original input from [[()]] to [()]
Apply the functions and then convert back to [[()]] before calling the converChar function recursively again?
The best answer I can come up with is that you should probably change your program so that your types represent what you want. Specifically, when I look at your code it seems that you have (or at least you think/you don’t have but wrote the wrong program):
Every [[(Int,Int,Int)]] is a list of the form [xs]
Every (Int,Int,Int) is either (0,0,0) or (1,1,1)
Firstly I will write down a solution to your problem as stated. Secondly I will show you how to construct types that represent the state of the wold (and don’t allow you to represent illegal states).
renderThing (0,0,0) = ' '
renderThing (1,1,1) = '█'
renderState = map (map renderThing)
Let’s describe this briefly. The first two lines define a partial function to do what your int-triple-to-char function, as described in the parent.
The third line defines the function you want. Let’s read it from left to right:
To renderState (which will have type [[(Int,Int,Int)]] -> [[Char]]):
Apply the map renderThing :: [(Int,Int,Int)] -> [Char] to each element of the list passed as input
To do that function, apply renderThing to each element of the inner list (I assume this is a row)
Unfortunately your program will crash if you ever violate your implicit invariant that any (Int,Int,Int) is either (0,0,0), or (1,1,1). One better type could be (Bool,Bool,Bool) as each element can then only have one of two values. Another way you could do this is:
data Thing = White | Black
There are two ways to put this into your program. Either use good types throughout so the compiler can make sure you never end up in an unexpected state, or you can have conversion functions which can have errors:
renderableBoard :: [[(Int,Int,Int)]] -> Either String [[Thing]]
renderableBoard = mapM (mapM convertOne) where
convertOne (0,0,0) = White
convertOne (1,1,1) = Black
convertOne x = "cannot concert to thing: " ++ show x

"For all" statements in Haskell

I'm building comfort going through some Haskell toy problems and I've written the following speck of code
multipOf :: [a] -> (Int, a)
multipOf x = (length x, head x)
gmcompress x = (map multipOf).group $ x
which successfully preforms the following operation
gmcompress [1,1,1,1,2,2,2,3] = [(4,1),(3,2),(1,3)]
Now I want this function to instead of telling me that an element of the set had multiplicity 1, to just leave it alone. So to give the result [(4,1),(3,2),3] instead. It be great if there were a way to say (either during or after turning the list into one of pairs) for all elements of multiplicity 1, leave as just an element; else, pair. My initial, naive, thought was to do the following.
multipOf :: [a] -> (Int, a)
multipOf x = if length x = 1 then head x else (length x, head x)
gmcompress x = (map multipOf).group $ x
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
Your diagnosis is right; the then and else must have the same type. There's no "getting past this issue," strictly speaking. Whatever solution you adopt has to use same type in both branches of the conditional. One way would be to design a custom data type that encodes the possibilities that you want, and use that instead. Something like this would work:
-- | A 'Run' of #a# is either 'One' #a# or 'Many' of them (with the number
-- as an argument to the 'Many' constructor).
data Run a = One a | Many Int a
But to tell you the truth, I don't think this would really gain you anything. I'd stick to the (Int, a) encoding rather than going to this Run type.

converting a list of string into a list of tuples in Haskell

I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]

Why am I receiving this syntax error - possibly due to bad layout?

I've just started trying to learn haskell and functional programming. I'm trying to write this function that will convert a binary string into its decimal equivalent. Please could someone point out why I am constantly getting the error:
"BinToDecimal.hs":19 - Syntax error in expression (unexpected `}', possibly due to bad layout)
module BinToDecimal where
total :: [Integer]
total = []
binToDecimal :: String -> Integer
binToDecimal a = if (null a) then (sum total)
else if (head a == "0") then binToDecimal (tail a)
else if (head a == "1") then total ++ (2^((length a)-1))
binToDecimal (tail a)
So, total may not be doing what you think it is. total isn't a mutable variable that you're changing, it will always be the empty list []. I think your function should include another parameter for the list you're building up. I would implement this by having binToDecimal call a helper function with the starting case of an empty list, like so:
binToDecimal :: String -> Integer
binToDecimal s = binToDecimal' s []
binToDecimal' :: String -> [Integer] -> Integer
-- implement binToDecimal' here
In addition to what #Sibi has said, I would highly recommend using pattern matching rather than nested if-else. For example, I'd implement the base case of binToDecimal' like so:
binToDecimal' :: String -> [Integer] -> Integer
binToDecimal' "" total = sum total -- when the first argument is the empty string, just sum total. Equivalent to `if (null a) then (sum total)`
-- Include other pattern matching statements here to handle your other if/else cases
If you think it'd be helpful, I can provide the full implementation of this function instead of giving tips.
Ok, let me give you hints to get you started:
You cannot do head a == "0" because "0" is String. Since the type of a is [Char], the type of head a is Char and you have to compare it with an Char. You can solve it using head a == '0'. Note that "0" and '0' are different.
Similarly, rectify your type error in head a == "1"
This won't typecheck: total ++ (2^((length a)-1)) because the type of total is [Integer] and the type of (2^((length a)-1)) is Integer. For the function ++ to typecheck both arguments passed to it should be list of the same type.
You are possible missing an else block at last. (before the code binToDecimal (tail a))
That being said, instead of using nested if else expression, try to use guards as they will increase the readability greatly.
There are many things we can improve here (but no worries, this is perfectly normal in the beginning, there is so much to learn when we start Haskell!!!).
First of all, a string is definitely not an appropriate way to represent a binary, because nothing prevents us to write "éaldkgjasdg" in place of a proper binary. So, the first thing is to define our binary type:
data Binary = Zero | One deriving (Show)
We just say that it can be Zero or One. The deriving (Show) will allow us to have the result displayed when run in GHCI.
In Haskell to solve problem we tend to start with a more general case to dive then in our particular case. The thing we need here is a function with an additional argument which holds the total. Note the use of pattern matching instead of ifs which makes the function easier to read.
binToDecimalAcc :: [Binary] -> Integer -> Integer
binToDecimalAcc [] acc = acc
binToDecimalAcc (Zero:xs) acc = binToDecimalAcc xs acc
binToDecimalAcc (One:xs) acc = binToDecimalAcc xs $ acc + 2^(length xs)
Finally, since we want only to have to pass a single parameter we define or specific function where the acc value is 0:
binToDecimal :: [Binary] -> Integer
binToDecimal binaries = binToDecimalAcc binaries 0
We can run a test in GHCI:
test1 = binToDecimal [One, Zero, One, Zero, One, Zero]
> 42
OK, all fine, but what if you really need to convert a string to a decimal? Then, we need a function able to convert this string to a binary. The problem as seen above is that not all strings are proper binaries. To handle this, we will need to report some sort of error. The solution I will use here is very common in Haskell: it is to use "Maybe". If the string is correct, it will return "Just result" else it will return "Nothing". Let's see that in practice!
The first function we will write is to convert a char to a binary. As discussed above, Nothing represents an error.
charToBinary :: Char -> Maybe Binary
charToBinary '0' = Just Zero
charToBinary '1' = Just One
charToBinary _ = Nothing
Then, we can write a function for a whole string (which is a list of Char). So [Char] is equivalent to String. I used it here to make clearer that we are dealing with a list.
stringToBinary :: [Char] -> Maybe [Binary]
stringToBinary [] = Just []
stringToBinary chars = mapM charToBinary chars
The function mapM is a kind of variation of map which acts on monads (Maybe is actually a monad). To learn about monads I recommend reading Learn You a Haskell for Great Good!
http://learnyouahaskell.com/a-fistful-of-monads
We can notice once more that if there are any errors, Nothing will be returned.
A dedicated function to convert strings holding binaries can now be written.
binStringToDecimal :: [Char] -> Maybe Integer
binStringToDecimal = fmap binToDecimal . stringToBinary
The use of the "." function allow us to define this function as an equality with another function, so we do not need to mention the parameter (point free notation).
The fmap function allow us to run binToDecimal (which expect a [Binary] as argument) on the return of stringToBinary (which is of type "Maybe [Binary]"). Once again, Learn you a Haskell... is a very good reference to learn more about fmap:
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
Now, we can run a second test:
test2 = binStringToDecimal "101010"
> Just 42
And finally, we can test our error handling system with a mistake in the string:
test3 = binStringToDecimal "102010"
> Nothing

Get a random list item in Haskell

After reviewing this SO question I am trying to use the random number generator to return a random list item based on the return of the randomIO generator.
Full Code:
module Randomizer where
import System.IO
import System.Random
data Action = Create | Destroy
deriving (Enum, Eq, Show)
type History = [Action]
-- | this looks at three sets of histories, and returns an appropriate Action
type ThreeHistoryDecisionMaker = History -> History -> History -> Action
allThreeDecisionMakers :: [ThreeHistoryDecisionMaker]
allThreeDecisionMakers = [decision1, decision2, decision3, decision4, decision5]
chooseRandomDecision :: [ThreeHistoryDecisionMaker] -> Int -> Strategy3P
chooseRandomDecision = allThreeDecisionMakers !! randomIO(0,4)
But I get the following errors:
special_program1.hs:249:16:
Couldn't match type ‘Action’
with ‘History -> History -> History -> Action’
Expected type: [[ThreeHistoryDecisionMaker] -> Int -> ThreeHistoryDecisionMaker]
Actual type: [ThreeHistoryDecisionMaker]
In the first argument of ‘(!!)’, namely ‘allThreeDecisionMakers’
In the expression: all3PStrategies !! randomIO (0, 4)
special_program1.hs:249:35:
Couldn't match expected type ‘(t0, t1) -> Int’
with actual type ‘IO a0’
The function ‘randomIO’ is applied to one argument,
but its type ‘IO a0’ has none
In the second argument of ‘(!!)’, namely ‘randomIO (0, 4)’
In the expression: all3PStrategies !! randomIO (0, 4)
Why is the first error block wanting to expect a list of everything inside it?
What does the second code block mean?
randomIO is not a "random function". Such a thing doesn't exist in Haskell, it wouldn't be referentially transparent. Instead, as the name suggests, it's an IO action which can yield a random value. It makes no sense to index a list with an IO action, !! randomIO(0,4) isn't possible. (It's impossible also for another reason: randomIO creates unlimited values, you want randomRIO (with an R for "range parameter") if you need to specify a (0,4) range.)
What you need to to do to get the value yielded by the action: well, monads! If you haven't learned the theory about those yet, never mind. A random-indexer could look thus:
atRandIndex :: [a] -> IO a -- note that this is gives itself an IO action
atRandIndex l = do
i <- randomRIO (0, length l - 1)
return $ l !! i
I suggest you actually use that function to implement your task.
But back to the code you posted... there's more problems. If you specify the type of chooseRandomDecision with two arguments, then you need to actually define it as a function of these arguments! But your definition doesn't accept any arguments at all, it merely uses the globally-defined list allThreeDecisionMakers (use of global variables never needs to be stated in the type).
Moreover, if you're choosing from a list of THDMakers, then the resulting element will also have that type, what else! So unless Strategy3P is simply another synonym of History -> History -> History -> Action, this won't do as a result, even if you contain it in the right monad.
This answer offers a simple, effective solution to the problem posed in the title: "Get a random list item in Haskell".
The package Test.QuickCeck provides a number of helpful, straightforward functions for generating random values (http://hackage.haskell.org/package/QuickCheck-2.7.6/docs/Test-QuickCheck.html#g:5). A function that returns random values from a list (wrapped IO) can be built by composing the QuickTest functions elements and generate:
import Test.QuickCheck (generate, elements)
randItem :: [a] -> IO a
randItem = generate . elements
chris Frisina's function chooseRandomDecision would then look like this:
chooseRandomDecision :: [ThreeHistoryDecisionMaker] -> IO ThreeHistoryDecisionMaker
chooseRandomDecision = randItem
The user Cale in the #haskell channel on freenode helped coach me to this solution.
note: This solution works with QuickCheck 2.7.6, but needs some alteration for earlier versions. You can update to the latest version with cabal install QuickCheck. See this question.

Resources