Returning different values of the same data type: - haskell

I'm writing a readValue function that can return any of Value's algebraic data types. The value constructors for Value aren't exported, so how can I return a Value?
Here's the documentation on Value.
Below is the function and the errors it produces:
readValue :: Label -> String -> Value
readValue label valueString =
case label of
"tags" -> (read valueString :: [String])
"text" -> (read valueString :: String)
src/Edit.hs:79:16:
Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: String
In the expression: (read valueString :: String)
In a case alternative: "text" -> (read valueString :: String)
In the expression:
case label of {
"tags" -> (read valueString :: [String])
"text" -> (read valueString :: String) }

You have:
readValue :: Label -> Value
You want:
readValue :: Label -> String -> Value
But:
(read valueString :: [String])
Has type [String] because that’s the type you gave it explicitly. Recall that :: has the lowest precedence. So the compiler is trying to unify String -> [String] with Value. That’s the source of your first error. The second error is caused by the :: String annotation on the second branch of the case, asking the compiler to try to unify String with [String], which too fails.
I suppose you want to wrap these values you’ve read into some of the Value constructors, which are indeed exported by Data.Bson, else you would be trying to return multiple different types from one function. But without knowing more about your problem, I can’t infer what you meant to do.

Here's the solution:
instance Val Value where
val = id
cast' = Just
readValue :: Label -> String -> Value
readValue label valueString =
case label of
"tags" -> val (read valueString :: [String])
"text" -> val (read valueString :: String)

Related

Make function with (Maybe a) parameter "generic"

let updateFunc = updatedMaybeProperty srcTitle targetTitle :: (Title -> Maybe a) -> Maybe a
_ = updateFunc (titleVersion :: Title -> Maybe Text)
_ = updateFunc (titleYearProduced :: Title -> Maybe Integer)
I get this error in line 3:
• Couldn't match type ‘Text’ with ‘Integer’
Expected type: Title -> Maybe Text
Actual type: Title -> Maybe Integer
• In the first argument of ‘updateFunc’, namely
‘(titleYearProduced :: Title -> Maybe Integer)’
Apparently, in line 2, the compiler infers the type for Maybe a and decides a must always be Text.
How can I prevent this and make updateFunc "generic" so that it works with different types for a?
Try annotating the binding, not the expression.
let updateFunc :: (Title -> Maybe a) -> Maybe a
updateFunc = updatedMaybeProperty srcTitle targetTitle
_ = updateFunc (titleVersion :: Title -> Maybe Text)
_ = updateFunc (titleYearProduced :: Title -> Maybe Integer)

How to create a newtype of parser?

newtype Parser a = PsrOf{
-- | Function from input string to:
--
-- * Nothing, if failure (syntax error);
-- * Just (unconsumed input, answer), if success.
dePsr :: String -> Maybe (String, a)}
I want to create a newtype of Parser to see how it looks like.
I tried
*ParserLib> PsrOf{"hello"}
But it comes up with an error
<interactive>:5:7: error: parse error on input ‘"’
You've already created the type. Now you want to create a value of that type. To do that, you need to call PsrOf with a value of type String -> Maybe (String, a). For example:
newtype Parser a = PsrOf { dePsr :: String -> Maybe (String, a) }
get3 :: String -> Maybe (String, Int)
get3 ('3':xs) = Just (xs, 3)
get3 _ = Nothing -- Any string, including the empty string, that doesn't start with '3'
get3P :: Parser Int
get3P = PsrOf get3
To actually use the parser, you need to extract the function before applying it to a string:
dePsr get3P "38" -- Just ("8", 3)
dePsr get3P "" -- Nothing
dePsr get3P "hello" -- Nothing
Record syntax here is just used to simplify the definition of the type, instead of writing
newtype Parser a = PsrOf (String -> Maybe (String, a))
dePsr :: Parser a -> String -> Maybe (String, a)
dPsr (PsrOf f) = f
The rest of the uses for record syntax (pattern matching or making slightly modified copies of a value) don't really apply usefully to types that wrap a single value.

Match type error when counting palindromes in a list in Haskell

I'm getting a match type [Char] with String -> Bool error:
isPalindrome :: String -> Bool
isPalindrome w = w == reverse w
countPalindromes :: [String] -> Int
countPalindromes ss = length (filter (== isPalindrome) ss)
countPalindromes uses isPalindrome to check if a string is a palindrome.
I now have a different issue than in my first question about this palindrome count task. The first issue was solved, and I was instructed to open a new question to solve the new issue. Which is why this is a different question.
isPalindrome :: String -> Bool, which is to say that it expects a string, then gives you a boolean to say whether or not that string is a palindrome.
(==) :: Eq a => a -> a -> Bool, which is to say that it expects two values of typeclass Eq (in other words: anything equatable) and tells you whether or not they are equal.
Pair those together and you get (== isPalindrome) :: (String -> Bool) -> Bool*. You've handed (==) a String -> Bool value, so it's expecting one more and will tell you if the two are equal. That's not quite what you want, though. You're not comparing two functions....
In fact, you're not comparing any two things at all. You only want to see which values passed to countPalindromes return True when called by isPalindrome. That's what filter is for!
filter :: (a -> Bool) -> [a] -> [a]
It's looking for an a -> Bool to pass as the first argument. This is the function that will be deciding what makes it through the filter and what doesn't, and in this case you want to use some derivation of isPalindrome. Looking again at isPalindrome in this context we see:
isPalindrome :: String -> Bool
that looks an awful lot like an a -> Bool function! Let's try substituting all the as in filter's type signature with String.
filter :: (String -> Bool) -> [String] -> [String]
That looks like it's exactly what you're wanting! Try, then, using filter isPalindrome instead of filter (== isPalindrome).
* nitpick: functions (more generally: values of type (-> r)) are not members of the Eq typeclass so you'd actually get an error saying that you can't tell if a String -> Bool is equal to another String -> Bool. It's not relevant to the problem at-hand, though, so I'm pretending that's not an issue and burying this explanation down here.

read::Int not working in Haskell in example

Here is the problem. It looks simple yet
main = do
s <- getContents
let list = map (read::Int) (words s)
print list
Couldn't match expected type `Int' with actual type `String -> a0'
Probable cause: `read' is applied to too few arguments
In the first argument of `map', namely `(read :: Int)'
In the expression: map (read :: Int) (words s)
The problem was that I thought :: is like casting and I have to put the return type. The solution was to add full wanted |function signature instread.
read is a function (of type Read a => String -> a), so it can't have type Int. You could do read :: String -> Int, or you could put a type signature on list rather than read, so you get:
let list :: [Int]
list = map read (words s)

Type synonym for Haskell giving type errors

I am attempting to create a type synonym that looks something like this:
data Result = Either String [Token]
I'm having difficulty because while this code compiles, when I attempt to create a Result with a [Token], haskell complains
Not in scope: data constructor `Result'
How can I define a type synonym with a constructor that works?!
How are you trying to create a Result??
The correct way is:
If you declare it as a data:
data Result = Result (Either String [Token])
f :: Result
f = (Result (Left "test"))
Or, if you declare as a type:
type Result = Either String [Token]
f :: Result
f = Left "test"
With
type Result = Either String Token
the data constructors are
Left :: String -> Result
Right :: [Token] -> Result
because
data Either a b = Left a | Right b
With
data Result = Either String [Token]
you declare Result to have one two-argument constructor, Either with type
Either :: String -> [Token] -> Result
which is a) probably not what you want and b) confusing, because Either is a well-known type constructor.
I think you need to use type and not data
type Result = Either String [Token]

Resources