import Data.Char (ord, chr)

-- A pythagorean number
pyths :: Int -> [(Int,Int,Int)]
pyths n = [(x,y,z) | x<-[1..n], 
		     y<-[1..n], 
		     z<-[1..n], 
                     x^2+y^2 == z^2]

-- Factors!!!!
factors :: Int -> [Int]
factors x = [n | n <- [1..x], x `mod` n == 0]

-- A positive integer is perfect if it equals the 
-- sum of all its factores excluding the number itself.
perfect :: Int -> Bool
perfect x | x<=0 = False
	  | otherwise = x == sum (tail (reverse (factors x)))


-- perfects returns the list of all perfect numbers up to a certain number
perfects :: Int -> [Int]
perfects x = [n | n <- [1..x], perfect n]

-- scalar product between two lists
--scalarProduct :: [Int] -> [Int] -> Int
scalarProduct xs = \ys -> sum [x*y | (x,y) <- zip xs ys]
				   

-- Book exercises

--
-- A list comprehension for the sum of many integers
--

sumMany :: Int -> Int
sumMany limit = sum [x*x | x <- [1..limit]]

--
-- Replicate with list comprehensions
--

replicateC :: Int -> a -> [a]
replicateC times element = [element | _ <- [1..times]]

--
-- Implement find and then implement positions using find
--

find :: Eq a => a -> [(a,b)] -> [b]
find n h = [pos | (x,pos) <- h, x == n]

positions :: Eq a => a -> [a] -> [Int]
positions n h = find n (zip h [1..(length h)])

--
-- Ceaser's cipher
--


letter2digit :: Char -> Int
letter2digit c = ord c - ord 'a'

digit2letter :: Int -> Char
digit2letter d = chr (d + ord 'a')

shift :: Int -> Char -> Char
shift offset = \char -> digit2letter ((letter2digit char + offset) `mod` 26)

{-
	both versions, with map and with comprehension, work! :-)
-}

encode :: Int -> [Char] -> [Char]
--encode offset = \s -> [shift offset c | c <- s]
encode offset = \s -> map (shift offset) s

decode :: Int -> [Char] -> [Char]
decode offset = \string -> [shift (-offset) c | c <- string]

count :: Char -> [Char] -> Int
count c string = length [1 | c' <- string, c == c']

countAll :: Fractional a => [Char] -> [a]
countAll string = map (\y -> y * 100)
			(map (\x -> (fromIntegral x) / fromIntegral (length string))
		      	    [count letter string | letter <- ['a'..'z']])

generateFrequencies :: Fractional a => [Char] -> [(Char, a)]
generateFrequencies string = zip ['a'..'z'] (countAll string)

table :: [Float]
table = [8.2, 1.5, 2.8, 4.3, 12.7, 2.2, 2.0,
         6.1, 7.0, 0.2, 0.8, 4.0, 2.4, 6.7,
         7.5, 1.9, 0.1, 6.0, 6.3, 9.1, 2.8,
         1.0, 2.4, 0.2, 2.0, 0.1]