variable not in scope - list comprehesion - haskell

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]

Related

Haskell, how to return a list without encountering an error

So I'm trying to wrap my head around Haskell with my first project where i have a function encountering an error:
Exception: prelude.head: empty list.
selectNextGuess :: [[Card]] -> [Card]
selectNextGuess lst
| length lst >= 1250 = lst !! (div (length lst) 2)
| otherwise = newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- lst]
(_, newGuess) = head(sort valuesList)
Any advice in steering me in the right direction to solve this would be greatly appreciated.
Cheers
TL;DR: since a list can be empty, and there is no minimal element in the empty list, the way to return a list without the error is to maybe return a list, or rather to return a Maybe list.
If you call selectNextGuess [], lst inside the function selectNextGuess becomes []. Then, valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- [] ] = [] is also an empty list. And then (_, newGuess) = head (sort valuesList) = head (sort []) = head [] is called.
But there is no head element in the empty list. This is what the error message is telling us. You called head with [], which is forbidden, because it has no answer.
The usual solution is to make this possibility explicit in the data type. We either have just one answer, for a non-empty list, or we have nothing:
data Maybe a = Just a | Nothing
is such built-in type. So we can use it, and handle the empty lst explicitly:
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| null lst = Nothing
| otherwise = Just newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x)
| x <- lst]
(_, newGuess) = head (sort valuesList)
Using null as a guard like that is a bit of an anti-pattern. We usually achieve the same goal with the explicit pattern in a separate clause, like
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess [] = Nothing
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| otherwise = Just newGuess
where ......
Using that head ... sort ... combination to find the minimal element is perfectly fine. Due to Haskell's lazy evaluation and the library sort being implemented as bottom-up mergesort, it will take O(n) time.
There is also a shorter way to write down the same thing,
....
| otherwise = listToMaybe . map snd $ sort valuesList -- or,
= listToMaybe [ x | (_, x) <- sort valuesList ] -- whichever you prefer.
where fbList = .....
valuesList = .....
Since there is no more than one value "inside" a Maybe _, the conversion function listToMaybe already takes just head element, implicitly.
Moreover, it produces Nothing automatically in the empty list [] case. So the explicit pattern clause can be removed, this way.

whats the advantage of using guards in Haskell?

count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+(count_instances x ts)
| otherwise = count_instances x ts
i just want to know whats so good about using guards in this Question ?
A guard can be a way to write only one half of an if-then-else expression; you can omit the else and have a partial function.
-- Leave the function undefined for x /= y
foo x y | x == y = ...
You can do the same with a case statement, but it's more verbose
foo x y = case x == y of
True -> ...
It's also easier to list several unrelated conditions as a set of alternatives than it is with a nested if-then-else or case expressions.
foo x y | p1 x y = ...
foo x y | p2 x y = ...
foo x y | p3 x y = ...
foo x y = ...
vs
foo x y = if p1 x y then ...
else (if p2 x y then ...
else (if p3 x y then ... else ...))
Patterns with guards are probably the most concise way to write code that otherwise would require nested case/if expressions.
Not the least advantage is that a where clause applies to all the guards right hand sides. This is why your example could be even more concise:
count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+rest
| otherwise = rest
where rest = count_instances x ts
A guard is haskell's most general conditional statement, like if/then/else in other languages.
Your code shows a straight forward implementation of counting contents of a list equal to a given parameter. This is a good example to learn how haskell's recursion works.
An alternative implementation would be
count_instances :: Int -> [Int] -> Int
count_instances i = length . filter (==i)
that reuses already existing functions from the Prelude module. This is shorter and probably more readable.

Haskell: List Comprehension / Hash Table Entries

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.

Project Euler #4 using Haskell

I hope this works by just pasting and running it with "runghc euler4.hs 1000". Since I am having a hard time learning Haskell, can someone perhaps tell me how I could improve here? Especially all those "fromIntegral" are a mess.
module Main where
import System.Environment
main :: IO ()
main = do
args <- getArgs
let
hBound = read (args !! 0)::Int
squarePal = pal hBound
lBound = floor $ fromIntegral squarePal /
(fromIntegral hBound / fromIntegral squarePal)
euler = maximum $ takeWhile (>squarePal) [ x | y <- [lBound..hBound],
z <- [y..hBound],
let x = y * z,
let s = show x,
s == reverse s ]
putStrLn $ show euler
pal :: Int -> Int
pal n
| show pow == reverse (show pow) = n
| otherwise = pal (n-1)
where
pow = n^2
If what you want is integer division, you should use div instead of converting back and forth to Integral in order to use ordinary /.
module Main where
import System.Environment
main :: IO ()
main = do
(arg:_) <- getArgs
let
hBound = read arg :: Int
squarePal = pal hBound
lBound = squarePal * squarePal `div` hBound
euler = maximum $ takeWhile (>squarePal) [ x | y <- [lBound..hBound],
z <- [y..hBound],
let x = y * z,
let s = show x,
s == reverse s ]
print euler
pal :: Int -> Int
pal n
| show pow == reverse (show pow) = n
| otherwise = pal (n - 1)
where
pow = n * n
(I've re-written the lbound expression, that used two /, and fixed some styling issues highlighted by hlint.)
Okay, couple of things:
First, it might be better to pass in a lower bound and an upper bound for this question, it makes it a little bit more expandable.
If you're only going to use the first two (one in your previous case) arguments from the CL, we can handle this with pattern matching easily and avoid yucky statements like (args !! 0):
(arg0:arg1:_) <- getArgs
Let's convert these to Ints:
let [a, b] = map (\x -> read x :: Int) [arg0,arg1]
Now we can reference a and b, our upper and lower bounds.
Next, let's make a function that runs through all of the numbers between an upper and lower bound and gets a list of their products:
products a b = [x*y | x <- [a..b], y <- [x..b]]
We do not have to run over each number twice, so we start x at our current y to get all of the different products.
from here, we'll want to make a method that filters out non-palindromes in some data set:
palindromes xs = filter palindrome xs
where palindrome x = show x == reverse $ show x
finally, in our main function:
print . maximum . palindromes $ products a b
Here's the full code if you would like to review it:
import System.Environment
main = do
(arg0:arg1:_) <- getArgs
let [a, b] = map (\x -> read x :: Int) [arg0,arg1]
print . maximum . palindromes $ products a b
products a b = [x*y | x <- [a..b], y <- [x..b]]
palindromes = filter palindrome
where palindrome x = (show x) == (reverse $ show x)

haskell - let/where equivalent within list comprehension?

Is there a way to use let,where or otherwise define sub-expressions in a list comprehension so that it can be used both in the term and constraint?
From my experimenting, the following work:
[let x = i*i in x | i<-[1..10], i*i > 20] --good
[i*i | i<-[1..10], let x=i*i in x > 20] --good
But these do not bc of scope:
[let x = i*i in x | i<-[1..10], x > 20] -- 'x' not in scope error
let x = i*i in [x | i<-[1..10], x > 20] -- 'i' not in scope error
[x | i<-[1..10], x > 20] where x = i*i --parse error on 'where'
So let works in one place or the other, but not both together!
The only way I've found to make it work (that is, avoid repeated expressions and possibly evaluations) is to add a silly singleton-list as I did here with x<-[cat i [1..k] as a constraint to the list comprehension:
> let cat x l = foldl1 (++) $ map show [x*i | i<-l]
maximum [x| i<-[1..9999], k<-[2..div 10 $ length $ show i], x<-[cat i [1..k]], sort x == "123456789"]
"932718654"
Or, contunuing the trivial example above,
[x | i<-[0..10], x<-[i*i], x > 20] --works
This seems a little silly, and is slightly lacking in clarity, tho it doesn't seem too inefficient. Still, it would be nice if let or where worked across the whole comprehension. Can this be done?
You write it like this:
[x | i <- [0..10], let x = i*i, x > 20]
Notice there is no in. You can refer to x in both the term, and any constraints following the let. This form of let corresponds to the one in do-notation:
do i <- [0..10]
let x = i*i
guard (x > 20)
return x
Here x is in scope from the let to the end of the do-block.
You almost had it; you can simply write [x | i <- [0..10], let x = i*i, x > 20] (note the , instead of in). It's very similar to do-notation (in fact, you can use do-notation instead, and a recent GHC extension enables you to use list comprehensions for arbitrary monads). If you're curious, you can find the syntax in the Haskell 98 report:
aexp -> [ exp | qual_1 , ... , qual_n ] (list comprehension, n >= 1)
qual -> pat <- exp (generator)
| let decls (local declaration)
| exp (guard)
As you can see, one of the valid qualifiers is let decls, which is exactly what you wanted.

Resources