I have a function that wants to list all of a dataType.
fn [] = []
fn (dt#(DataType t d y [(f,r)]):dts) = ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)] ++ fn dts
Where t and d are strings, y is an int, f is a string and r is an int (not sure f and r matter though, will explain furthur on).
I got the error non-exhaustive patterns, and presumed it was because I didn't have one for when there was only one element in the list, so I added this between the other patterns:
fn [dt#(DataType t d y [(f,r)])] = ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
It compiled, but when I called the function it once again told me 'non-exhaustive patterns'. I'm struggling to think of what pattern i've missed, should I add a wildcard pattern afterward to catch everything? I'm not looking for someone to type out the answer, but hints or suggestions are welcome.
The pattern [(f,r)] only matches when the list contains one element. If it contains zero, or two, or any other number, you have a pattern match failure.
What the code should do in this instance, I couldn't say...
You do already cover the one-element-list case: that matches fn (dt#(DataType t d y [(f,r)]):[]), since dts can be anything including the empty list.
Indeed there's no reason to use explicit recursion here: you basically have something like
f [] = []
f (x:xs) = g x ++ f xs
Compare that to the monad instance of lists:
instance Monad [] where
return x = [x]
[] >>= _ = []
(x:xs) >>= g = g x ++ (xs >>= g)
So you should write you function as
fn l = l >>= \dt#( DataType t d y [(f,r)] )
-> ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
That won't fix your problem though, but it makes it obvious what's going on: evidently, DataType t d y [(f,r)] is not the only valid pattern for that type. As MathematicalOrchid points out, [(f,r)] matches only a list with length 1, but you need to cover other lengths as well.
fn l = l >>= \dt -> case dt of
DataType t d y [(f,r)]
-> ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
DataType t d y []
-> ["Some other stuff"]
DataType t d y [(f,r), ...]
-> ["Yet other stuff"]
or whatever.
Indeed, if you only ever return [ ("stuff") ] here, then you're not really using the monadic bind functionality at all: you could have written the recursive version without ++, only reconstruct the thing with :, and in fact you have simply a map operation:
fn = map $ \dt -> case dt of
DataType t d y [(f,r)]
-> "T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)
DataType t d y []
-> "Some other stuff"
DataType t d y [(f,r), ...]
-> "Yet other stuff"
Related
When I run the following code:
main = do
let smallTriplets xs ys zs = [ (x, y, z) | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
print (smallTriplets [1,2] [3,4] [5,6])
It gives the output:
[(1,3,5),(1,3,6),(1,4,5),(2,3,5)]
However, I want smallTriplets to print the sum with some customization. To be more specific, it will be better if I could replace let sum = x + y + z in smallTriplets with some code so that it gives output like:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
I am expecting that code to have a string like "Sum is " ++ show(x) ++ "+" ++ show(y) ++ "+" ++ show(z) ++ " = " ++ show(x + y + z) ++ "\n"
How can I do that?
If this is not possible then please show me how to print:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
What's the problem of writing "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show sum instead of (x, y, z)?
You could like this
main = do
let helper x y z s = "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show s
let smallTriplets xs ys zs = [ helper x y z sum | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
putStr $ unlines $ smallTriplets [1,2] [3,4] [5,6]
Here, smallTriplets returns a [String] instead of a [(,,)]; unlines converts the [String] to a String with embedded \ns; finally, putStr prints the string.
This is a quick and dirty solution which alters the function smallTriplets, so if you planned to use the original result in other ways this solution will not help.
If your aim is to log things you do, then a more complex solution is needed. Maybe using the writer monad?
I do have the following code:
suffixes :: [a] -> [[a]]
suffixes [] = [[]]
suffixes l#(_:t) = l : suffixes t
prefixes :: [a] -> [[a]]
prefixes [] = [[]]
prefixes l#x = l : prefixes (init x)
menu :: Char -> [a] -> Either String [[a]]
menu 'p' l = Right (prefixes l)
menu 's' l = Right (suffixes l)
menu x _ = Left ("(" ++ show x ++ ")" ++ "is not supported, use (p)refix or (s)uffix")
I do have the following test function:
testMenuP = "Expected Right [[1,2],[1],[]]; menu 'p' [1,2] returned " ++ show (menu 'p' [1,2] :: Either String [[Int]])
testMenuS = "Expected Right [[1,2],[2],[]]; menu 's' [1,2] returned " ++ show (menu 's' [1,2] :: Either String [[Int]])
testMenuC = "Expected Left \"(d) is not supported, use (p)refix or (s)uffix\"; menu 'd' [1,2] returned " ++ show (menu 'd' [1,2] :: Either String [[Int]])
testMenu = putStr (testMenuP ++ "\n" ++ testMenuS ++ "\n" ++ testMenuC ++ "\n")
My question is now, how do I get rid of the quotes '' in the Char 'd' when I output the string (as shown in the test function testMenuC).
You can replace the part of menu with:
menu x _ = Left ("(" ++ [x] ++ ")" ++ "is not supported, use (p)refix or (s)uffix")
or even
menu x _ = Left . mconcat $ ["(", [x], ")", "is not supported, use (p)refix or (s)uffix"]
I am trying to write a function which outputs all variable names. When used on the example below, the output should be
*Main> used example
["a","b","x","y"]
This is what I have written so far...
import Data.Char
import Data.List
type Var = String
data Term =
Variable Var
| Lambda Var Term
| Apply Term Term
-- deriving Show
instance Show Term where
show = pretty
example :: Term
example = Lambda "a" (Lambda "x" (Apply (Apply (Lambda "y" (Variable "a")) (Variable "x")) (Variable "b")))
pretty :: Term -> String
pretty = f 0
where
f i (Variable x) = x
f i (Lambda x m) = if i /= 0 then "(" ++ s ++ ")" else s where s = "\\" ++ x ++ ". " ++ f 0 m
f i (Apply n m) = if i == 2 then "(" ++ s ++ ")" else s where s = f 1 n ++ " " ++ f 2 m
used :: Term -> [Var]
used (Variable n) = [n]
used (Lambda n t) = "\\" ++ n ++ ". " ++ used t
used (Apply t1 t2) = used t1 ++ used t2
The problem lies in the line used (Lambda n t) = "\\" ++ n ++ ". " ++ used t, I get this error message:
list.hs:28:47: error:
lexical error in string/character literal at character '\n'
|
28 | used (Lambda n t) = "\" ++ n ++ ". " ++ used t
Why am I getting this complaint?
You are copying and pasting from examples too much. Keep thinking about what the function is supposed to mean as you are writing it.
used (Variable n) = [n]
This is correct: the set of variables used in a term which is just a variable is the variable used. For example, the set of variables used in the term x is just [x].
used (Apply t1 t2) = used t1 ++ used t2
This is also correct1: the set of variables used in say (x y z) (w x y) is the union of the variables used in x y z and in w x y: that is [x,y,z,w,x,y].
So now let's consider the case you are struggling with.
used (Lambda n t) = ...
The code you have seems to be attempting to print the the term into a string, which is not what we are trying to do here -- we are trying to find the set of used variables.
Let's consider an example: we have a term like (\x. x y z), and we want to find out what its used variables are. Before trying to come up with the general solution, ask yourself what the result should be in this example.
If this function is going to be nicely recursive, can we express your expected result in terms of the used variables of x y z? How do we transform the set of used variables of x y z into the set of used variables of \x. x y z?
1 Though you might get duplicates.
I have been trying to to iterate the cand data in order to apply a function "pt_string".
Pt :: (Float, Float)
Person :: (Pt, Pt, [Pt], Float)
My idea is to call that function "pt_string" in a different way for each element of the tupple.
For example:
pt_string Point (first)
map pt_string [Point]
pt_string Point (second)
show "Tmp"
So far, I got:
pt_string :: pt -> String
pt_string pt = "(" ++ show (fst pt) ++ "," ++ show (snd pt) ++ ")\n"
Which works fine. But how can I create cand_to_string :: cand -> String in the above order?
Thanks!
Assuming
type Candidate = (Point, Point, [Point], Float)
you can use
candidate_to_string :: Candidate -> String
candidate_to_string (p1, p2, ps, f) =
"(" ++
point_to_string p1 ++ ", " ++
point_to_string p2 ++ ", " ++
points_to_string ps ++ ", " ++
show f ++
")"
which relies on
points_to_string :: [Point] -> String
points_to_string ps = "[" ++ intercalate ", " (map point_to_string ps) ++ "]"
exploiting Data.List.intercalate to add commas between the points.
Also note that, if you simply want the standard list/tuple printing format, you can directly use
candidate_to_string :: Candidate -> String
candidate_to_string = show
I'm working on a way of representing memory in Haskell that looks like this...
data MemVal = Stored Value | Unbound
deriving Show
type Memory = ([Ide],Ide -> MemVal)
As an Identifier is called its added to the list of Identifiers. If an error occurs in the program I want to be able to recall the identifiers used up to date. So far I have this...
display :: Memory -> String
display m = "Memory = " ++ show (map (snd m) (fst m)) ++ " "
But was wondering if there were a way to map the name of the identifier to (fst m) as well as the function (snd m) so the output will be similar to...
Memory = [sum = stored Numeric 1, x = stored Boolean true]
Thank you.
You probably want something like this
display :: Memory -> String
display (ides, mem) =
"Memory = [" ++ unwords (map (\x -> x ++ "=" ++ mem x) ides) ++ "]"
I'm guessing this is what you are after:
import Data.List (intercalate)
display (Memory ids f) = "Memory = [" ++ (intercalates ", " assigns) ++ "]"
where assigns = [ show i ++ " = " ++ show (f i) | i <- ids ]
Here assigns is a list like:
[ "sum = stored Numeric 1", "x = stored Boolean true", ...]
and intercalate ", " assigns joins the strings together.
I've used destructuring to avoid having to refer to fst ... and snd ...