like consider the following python code,
n = 4
if n>3 :
n = 5
if n>2 :
n = 6
if n>1 :
n = 4
How to achieve this in haskell??
let n = 4
main :: IO()
main = do
if n>3 then let n = 5
if n>2 then let n = 6
if n>1 then let n = 4
Tried this but gives an error, looking for some modifications
As I commented there are some points of your program you should checkout
else must be used after if
You don't use let for top level declarations (as in let n = 4).
When you write if n>3 then let n=5 you are not changing the value of n because values are inmutables in Haskell
There are a few "idiomatic" ways you can rewrite your program
Use a chained if then else with prints. This is the closest to your code
n = 4 -- no let in top level binding
main :: IO()
main = do
if n>3 then print 5 -- do not use let n=5 because n can't be mutated
else if n>2 then print 6
else if n>1 then print 4
else print ()
Use an external function and guards. This is the most idiomatic
f :: Int -> Int
f x | x > 3 = 5
| x > 2 = 6
| x > 1 = 4
n = 4
main = do
print (f n)
As #davidflecher commented, you can use guards within a let binding
n = 4
main :: IO()
main = do
let x | n > 3 = 5
| n > 2 = 6
| n > 1 = 4
print x
Use MultyWayIf extension (This is more advance as it needs extensions to the language)
{-# LANGUAGE MultiWayIf #-}
n = 4
main :: IO()
main = do
let x = if | n > 3 -> 5
| n > 2 -> 6
| n > 1 -> 4
print x
While the example is a bit contrived, the usual way to encode an if with multiple branches is to use a case-of with () as the scrutinee as follows:
main :: IO()
main = do
case () of
_ | n > 3 -> ...
| n > 2 -> ...
| otherwise -> ...
or when part of a binding, by use of a guarded let
let x | n > 3 = ...
| n > 2 = ...
| otherwise = ...
Alternatively, this may also be encoded as guards of a helper function
f :: Int -> Int
f n | n > 3 = 5
| n > 2 = 6
| otherwise = 4
Updated to include #Iceland_jack's comment
This is the code I have so far:
data Suit = Diamond | Club | Heart | Spade
deriving (Read, Enum, Eq, Bounded)
data Rank = Two | Three | Four
| Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Read, Enum, Eq, Ord, Bounded)
and I am trying to map each value, either Rank or Suit to a unique prime number.
primeMapper :: Either Rank Suit -> Int
should be the final function and I want to iterate over each Suit and set it to the first four primes:
primeMapper [Diamond .. Spade] = [2,3,5,7]
and each Rank equal to the rest of the primes up until the 17th:
primeMapper [Two .. Ace] = drop 4 . take 17 $ primes
assuming I have a generating function called primes.
This code, however throws errors obviously because it generates a list from a list. How can I achieve what I am trying to do? Let me know if I can explain it better.
The ultimate goal is to have a hash table that gives unique IDs to each cards based on prime factors, and then generate prime factorization and use modulo to quickly compare poker hands.
Ultimately I solved what I am trying to do by hand as so:
primeMapper :: Either Suit Rank -> Int
primeMapper x = case x of
Left Diamond -> 2
Left Club -> 3
Left Heart -> 5
Left Spade -> 7
Right Two -> 11
Right Three -> 13
Right Four -> 17
Right Five -> 19
Right Six -> 23
Right Seven -> 29
Right Eight -> 31
Right Nine -> 37
Right Ten -> 41
Right Jack -> 43
Right Queen -> 47
Right King -> 53
Right Ace -> 59
... was there a more concise way to do this rather than write each case out by hand?
Your solution using pattern matching is best, though I would prefer
primeMapper :: Either Suit Rank -> Int
primeMapper (Left Diamond) = 2
primeMapper (Left Club) = 3
...
rather than your long case expression.
However you could also use lookup :: Eq a => a -> [(a, b)] -> Maybe b
import Data.Maybe (fromJust)
primeMapper :: Either Suit Rank -> Int
primeMapper = fromJust . flip lookup zippedPrimes
where
zippedPrimes = zip suitranks primes
suitranks = fmap Left suits ++ fmap Right ranks :: [Either Suit Rank]
suits = fromEnum minBound
ranks = fromEnum minBound
Depending on what you plan to use this for, you may not need to use primes or prime factorizations at all; you can get fast conversion to and from plain numbers just by picking one or the other of the suit or rank for a base conversion. Here I'll pick suit -- there are four suits, so take the first digit in base 4 as the suit and the remaining digits as the rank.
encode :: (Suit, Rank) -> Int
encode (s, r) = fromEnum s + 4 * fromEnum r
decode :: Int -> (Suit, Rank)
decode n = (toEnum s, toEnum r) where (r, s) = n `quotRem` 4
You can verify in ghci that this gives a unique number to each card:
> [encode (s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51]
And that they decode appropriately:
> map decode [0..51] == [(s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
True
You can adapt some of this I hope.
no2s3s5s = \n -> take n $ scanl (\b a -> a+b) 11 $ cycle [2,4,2,4,6,2,6,4]
rnk = filter (/=49) $ no2s3s5s 14
stv = [2,3,5,7]
_deck = [ b*v | b <- stv, v <- rnk]
_Dia = take 13.drop (0*13) $ _deck
_Clb = take 13.drop (1*13) $ _deck
_Hrt = take 13.drop (2*13) $ _deck
_Spd = take 13.drop (3*13) $ _deck
_Dia
[22,26,34,38,46,58,62,74,82,86,94,106,118]
_Clb
[33,39,51,57,69,87,93,111,123,129,141,159,177]
_Hrt
[55,65,85,95,115,145,155,185,205,215,235,265,295]
_Spd
[77,91,119,133,161,203,217,259,287,301,329,371,413]
_deck
[22,26,34,38,46,58,62,74,82,86,94,106,118,33,39,51,57,69,87,93,111,123,129,141,159,177,55,65,85,95,115,145,155,185,205,215,235,265,295,77,91,119,133,161,203,217,259,287,301,329,371,413]
length _deck
52
Your multiples (_deck) are all unique.
I normally use no2s3s5s with a computed (limited) factor list and the mod function to generate a long prime list.
This is my code:
import Data.Bits
main = print . sum . takeWhile( < 200000) $ multSum 999
multSum m = 3 : multiples [6..m] where
multiples (p:xs)
| ((p `mod` 3 == 0) || (p `mod` 5 == 0)) = p : multiples([p..m])
| otherwise = p : xs
Error: out of memory (requested 1048576 bytes)
Where am I going wrong?
multSum isn't doing what you think it is. Try debugging it directly:
*Main> take 20 $ multSum 999
[3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6]
multSum returns the infinite list [3,6,6,6,6...] for all arguments, thus it never exceeds 200000 and so the sum you request can't be printed.
try
mults35 m = multiples [3..m] .....
............
....| ...... = p : multiples xs
... | otherwise = multiples xs
there will be one more thing for you to add there. Try this, and you'll see.
I have datatype:
data SidesType = Sides Int Int Int deriving (Show)
And I need a function which get a list of SidesType and remove duplicates from it.
*Main> let a = [Sides 3 4 5,Sides 3 4 5,Sides 5 12 13,Sides 6 8 10,Sides 6 8 10,Sides 8 15 17,Sides 9 12 15,Sides 5 12 13,Sides 9 12 15,Sides 12 16 20,Sides 8 15 17,Sides 15 20 25,Sides 12 16 20,Sides 15 20 25]
*Main> removeDuplicateFromList [] a
[Sides 3 4 5,Sides 5 12 13,Sides 6 8 10,Sides 6 8 10,Sides 8 15 17,Sides 9 12 15,Sides 5 12 13,Sides 9 12 15,Sides 12 16 20,Sides 8 15 17,Sides 15 20 25,Sides 12 16 20,Sides 15 20 25]
Here is my solution:
removeElementFromList :: [SidesType] -> SidesType -> [SidesType]
removeElementFromList lst element =
let (Sides a b c) = element
in [(Sides x y z) | (Sides x y z) <- lst, (x /= a) || (y /= b)]
removeDuplicateFromList :: [SidesType] -> [SidesType] -> [SidesType]
removeDuplicateFromList inlist outlist
| (length outlist) == 0 = inlist
| otherwise =
let element = head outlist
b = tail outlist
filtered = removeElementFromList b element
in removeDuplicateFromList (inlist ++ [element]) filtered
I am just wondering if there is any other way to write this code in more haskell-way ?
As usual there is "By" function which adds flexibility:
nubBy :: (a -> a -> Bool) -> [a] -> [a]
PS Although it's O(n^2)
You're already deriving Show for your datatype. If you also derive Eq, you can use nub from module Data.List.
Use Data.List.nub
First derive the order class also:
data XYZ = XYZ .... deriving (Show, Eq, Ord)
Or write your on Eq instance:
instance Eq XYZ where
a == b = ...
Then be intelligent and use a Tree! [Computer Science Trees grow from top to bottom!][1]
import qualified Data.Map.Strict as Map
removeDuplicates ::[a] -> [a]
removeDuplicates list = map fst $ Map.toList $ Map.fromList $ map (\a -> (a,a)) list
Complexity (from right to left) for list with length N:
map of the list: O(N)
Map.fromList: O(N*log N)
Map.toList: O(log N)
map over list with list length smaller or equal to N: O(N)
They are called consecutively, this means, there are pluses between the complexities of the parts => O(2 * N + N * log N + log N) = O(N * log N)
This is way better than traversing N^2 times over the list!
See: wolframAlpha plots. I included 2*N also for comparison reasons.
2+3: http://hackage.haskell.org/package/containers-0.5.4.0/docs/Data-Map-Strict.html
[1]: Search wikipedia for Computer Science Tree