In a parallel list comprehension in Haskell, I encounter a problem when trying to use a guard.
largestPalindrome :: Int -> Int
largestPalindrome x = maximum [ a*b
| a <- [x,x-1..1]
| b <- [x,x-1..1]
, isPalindrome (a*b) ]
The error that is displayed is
Variable not in scope: a :: Int
Quoted from Haskell Prime:
Parallel comprehensions extend list comprehensions with a notation for
zips. The comprehension
[ e | quals1 | ... | qualsN ]
can be desugared to
zipWithN (\ p1 ... pN -> e) [p1 | quals1] ... [pN | qualsN]
where pi
is a tuple of the variables defined by qualsi and used by e.
So, from your example, [a*b |a<- [x,x-1..1] | b <- [x,x-1..1] , isPalindrome (a*b)] is roughly equivalent to
zipWith (\a b -> a*b)
[ a | a<-[x,x-1..1] ]
[ b | b <- [x,x-1..1], isPalindrome (a*b) ]
where it is pretty clear why a is not in scope for the last list comprehension. Intuitively, you should think of each | delimited part as being completely independent from the others. Any filtering operation is going to be bound to only one of these parts.
Related
I am new to Haskell and I am trying to calculate the maximum segment sum,
(#) :: Int -> Int -> Int
x # y = 0 `max` (x + y)
mss2 :: [Int] -> Int
mss2 = maximum . scanr (#) 0
The error is
No Modules Loaded for (#)
I found this snippet in Richard Bird's text.
What am I missing here?
Are there other ways to declare/overload the operators, is my approach wrong?
It appears that in the context of that book, (#) is being used as a stand-in for some binary operator such as (+) or (<>), even though this is not actually legal Haskell syntax†.
For questions about Haskell syntax, it’s helpful to consult the Haskell 2010 Report.
In Ch. 2 Lexical Structure, under §2.2 Lexical Program Structure, you can find # in the grammar of symbols that may appear in an operator name:
symbol → ascSymbol | uniSymbol⟨special | _ | " | '⟩
ascSymbol → ! | # | $ | % | & | ⋆ | + | . | / | < | = | > | ? | #
| \ | ^ | | | - | ~ | :
And §2.4 Lexical Structure: Identifiers and Operators defines valid operator names to include such symbols:
varsym → ( symbol⟨:⟩ {symbol} )⟨reservedop | dashes⟩
consym → ( : {symbol} )⟨reservedop⟩
However, the subscript in angle brackets denotes a “difference” or exclusion, so this disallows a list of reserved identifiers. Under the production reservedop you can find that # appears in that list:
reservedop → .. | : | :: | = | \ | | | <- | -> | # | ~ | =>
The reason is that the # symbol denotes an “as” pattern, described in §3.17.2.8 Informal Semantics of Pattern Matching:
Matching an as-pattern var#apat against a value v is the result of matching apat against v, augmented with the binding of var to v.
As patterns are very useful for controlling the sharing of values and making certain definitions more concise, e.g.:
-- | Merge two sorted lists.
merge :: (Ord a) => [a] -> [a] -> [a]
-- ‘as0’ & ‘bs0’ denote the original input lists.
-- ‘as’ & ‘bs’ denote their tails.
merge as0#(a : as) bs0#(b : bs) = case compare a b of
-- ‘as0’ passes along the same list cell;
-- repeating ‘a : as’ would allocate a /new/ cell.
GT -> b : merge as0 bs
_ -> a : merge as bs0
merge [] bs0 = bs0
merge as0 [] = as0
Therefore, the definition:
x # y = 0 `max` (x + y)
Or more conventionally written x#y = …, is equivalent to defining two variables referring to the same value, which furthermore is defined recursively:
x = 0 `max` (x + y)
y = x
Without the type signature Int -> Int -> Int, this definition would be accepted, defining x, y :: (Ord a, Num a) => a, but attempting to evaluate either variable would produce an infinite loop, since this is “unproductive” recursion.
The solution is to use a non-reserved symbol as your operator name instead, such as <#> or +..
† I can’t find a citation for this, but it’s possible that GHC used to accept this syntax, even though it was also disallowed by the Haskell 98 Report which was current at the time the first edition of this book came out, and that this example code just wasn’t updated for the second edition.
This question already has an answer here:
Haskell function :: [Name] -> [[(Name, Bool)]]
(1 answer)
Closed 4 years ago.
Having a list of ["P", "Q", "R" ...] I want to generate all possible list of [(String, Bool)] where on the left is a letter from the first array, and on the right is True or False. For example having ["P", "Q"] I want to obtain
: [[("P",True),("Q",True)],[("P",True),("Q",False)],[("P",False),("Q",True)],[("P",False),("Q",False)]]
I made it for the case where I only have ["P", "Q"] but I need to suport arbitrary number of letters. I tought I can generate for every letter L two pairs in an array like [(L,True),(L,False)] and do that for every letter and make all possible combinations of those arrays with one element from each array, but I don't know how to do it properly.
That's what I did for the list of length 2 of letters
envs :: [String] -> [[(String, Bool)]]
envs predicate = let
env = [(p,b) | p <- predicate, b <- [True, False]]
ps = filter (\(pred,val) -> pred == "P") env
qs = filter (\(pred,val) -> pred == "Q") env
in [[a,b] | a <- ps, b <- qs]
Introduce this function
cartProdn :: [a] -> Int -> [[a]]
cartProdn ls 2 = [[x, y] | x <- ls, y <- ls]
cartProdn ls n = [x : t | x <- ls, t <- cartProdn ls (n - 1)]
This gives all possible combinations of length n of a finite list (n > 1).
Then do
*Main> ls = ["P", "Q", "R"]
*Main> rs = [zip ls c | c <- cartProdn [True, False] (length ls)]
*Main> putStrLn $ unlines $ map show rs
[("P",True),("Q",True),("R",True)]
[("P",True),("Q",True),("R",False)]
[("P",True),("Q",False),("R",True)]
[("P",True),("Q",False),("R",False)]
[("P",False),("Q",True),("R",True)]
[("P",False),("Q",True),("R",False)]
[("P",False),("Q",False),("R",True)]
[("P",False),("Q",False),("R",False)]
note: you might want to write ls = "PQR".
I'm trying construct a function that return a list with the sum of tuples elements when is higher than 100.
resultSum :: [(Integer)] -> [Integer]
resultSum (x:xs) = [ sumT | let sumT = fst x + snd x in sumT + trd x, sumT > 100 ]
trd (_,_,x) = x
I'm receiving the message:
Not in scope: `sumT'
I figured that when I use the let I'm specifying who is my variable
PS: I need to user letand list comprehesion
I assume you want to get all 3-tuples in a list of 3-tuples where the sum of the components is greater than 100 and you want somehow to use let inside the listcomprehension.
First of all: the type of your expression is not correct, it should probably be:
resultSum :: [(Integer,Integer,Integer)] -> [Integer]
Try the following solution:
resultsum xs3 = [x+y+z | (x,y,z) <- xs3, let sumT=x+y+z in sumT>100]
BTW: The let in right of the | is local to the right part of |, you cannot use it left of |. However, you can use let as a standalone clause on the right side of | (thank chi) and then you can use it on the left side of | like
resultsum xs3 = [sumT | (x,y,z) <- xs3, let sumT=x+y+z, sumT>100]
I want to make a function that takes in a string of multiple "grades" of varying length and convert it to a list of grades.
Grade is just a data structure that looks like this (just an arbitrary grading system):
data Grade = A+ | A | A- | B+ | B | B- | P | F
deriving (Show, Eq)
As you can see, the grades have varying length. If they had length 1 or consistent length, this would have been much easier.
Here is the function that I want to make:
This is what the string input looks like "PA+FABA+B-A"
stringToGrade :: String -> Grade
stringToGrade stringGrade
| stringGrade == "A+" = A+
| stringGrade == "A" = A
-- and so on
extractGrades :: String -> [Grade]
extractGrades stringGrades = case stringGrades of
[] -> []
x:y:ys
| x == "A" && y == "+" -> [stringToGrade (x : y)] : extractGrades ys
| x == "A" -> [stringToGrade x] : extractGrades y:ys
-- and so on
As you can see, this is not going anywhere.
Is there an elegant and easy way I cam do this instead of had coding everything?
We can apply pattern matching so to match a string prefix. Here's an example:
foo :: String -> [Int]
foo [] = []
foo ('h':'e':'l':'l':'o':rest) = 1 : foo rest
foo ('b':'o':'b':rest) = 2 : foo rest
foo ('b':rest) = 3 : foo rest
foo _ = error "foo: invalid input syntax"
Sample usage:
foo "hellobbobbobhello" ==> [1,3,2,2,1]
You can split the string into tokens using combination of split functions.
split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
will create this form, where the suffixes are attached.
["PA+","FABA+","B-","A"]
Now, you can split this further with a custom splitter
splitInit [] = []
splitInit [x] = [[x]]
splitInit [x,y] = [[x,y]]
splitInit (x:xs) = [x] : splitInit xs
a combination will give you
concatMap splitInit $ split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
["P","A+","F","A","B","A+","B-","A"]
where you can map through your constructors
I'm trying to place a bunch of words into a hash table based on length. The words are stored in
data Entry = Entry {word :: String, length :: Int} deriving Show
Now, I've got all the words stored in "entries", which is a list of Entry. Then, my hash table is defined as follows:
type Hash = [Run]
type Run = [Entry]
Now I'm trying to figure out how to get the entries into the hash table. The following is my current attempt
maxL = maximum [length e | e <- entries]
runs = [r | r <- [e | e <- entries, length e == i]] where i = [1..maxL]
Compiler's obviously telling me that Int can't be compared to [Int], but I don't know how to say
e | e <- entries, e has length i
Any help is much appreciated!
Cheers
Your code is almost OK:
maxL = maximum [length e | e <- entries]
runs = [r | r <- [e | e <- entries, length e == i]] where i = [1..maxL]
except that where doesn't work that way. It's not a synonym for foreach; but for let:
runs = let i = [1..maxL]
in [r | r <- [e | e <- entries, length e == i]]
So, length e is an integer, but i is [1..maxL] which is a list of integers. You intended for i to take on the values in [1..maxL] one-by-one, and that's done by <- binding in list comprehension:
runs = [ [r | r <- [e | e <- entries, length e == i]] | i <- [1..maxL]]
Now, [r | r <- xs] is the same as just xs, so it becomes
runs = [ [e | e <- entries, length e == i] | i <- [1..maxL]]
With "standard" functions, this is written as
import Data.List (sortBy)
import Data.Ord (comparing)
runs = group $ sortBy (comparing length) entries
It is also better algorithmically. Although, it won't have empty runs for non-existent lengths, so the two aren't strictly equivalent. But that can be fixed with another O(n) pass over the results, with
-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
runs' = snd $ mapAccumL
(\a# ~((k,g):t) i-> if null a || i<k then (a,[]) else (t,g))
[ (length $ head g, g) | g<- runs]
[ 1..maxL]
You're looking for the groupBy function from Data.List. You have a list of strings, which you want to group by their lengths. The groupBy function has type (a -> a -> Bool) -> [a] -> [[a]]. The second parameter is your input list and the first is a function that you need to write, which should take two strings and compare their lengths. It will return a list of lists of strings, where each sub-list will be containing strings of equal length.
By the way, if you want to write this succinctly, look at the on combinator from Data.Function.