{-# LANGUAGE TupleSections #-} module Exercise_12 where import Data.List (nub, partition, sort, (\\), sortOn, permutations, find) import Data.Bifoldable (biconcat) import Data.Function import Data.Functor ((<$>), (<&>)) import Data.Maybe import Control.Arrow import Control.Monad import GHC.Char import System.IO {-H12-} isPrime :: Int -> Bool isPrime n | n <= 1 = False | otherwise = primeAux (n-1) where primeAux 1 = True primeAux i = n `mod` i /= 0 && primeAux (i-1) -- returns all primes up to the passed number primes :: Int -> [Int] primes n = [i | i<-[2..n], isPrime i] {-WETT-} {- MCCOMMENT Cheatsheet for Wettbewerb-exercises for anyone next year reading this: <<< infixr 1 >>> infixr 1 =<< infixr 1 >>= infixl 1 $ infixr 0 & infixl 1 . infixr 9 <*> infixl 4 <$> infixl 4 <&> infixl 1 & infixl 1 (>>=) :: (a -> b) -> (b -> a -> c) -> (a -> c) (<*>) :: (a -> b -> c) -> (a -> b) -> (a -> c) Also, I want yjtools for this operator alone: (<.>) :: Functor f => (a -> b) -> (c -> f a) -> c -> f b ...namely, (fmap f .) is then equivalent to (f <.>) -} encrypt :: String -> String encrypt x = isPrime `map` enumFrom 1 `zip` x & partition fst & biconcat <&> snd {- pointfree variant, more tokens. encrypt = map snd . biconcat . partition fst . zip (isPrime <$> enumFrom 1) -} decrypt :: String -> String decrypt = map snd <<< -- this still makes sense, keep in mind “ <<< = . ”, “ >>> = flip (<<<) ” sort <<< -- first tuple elem is just naturals, so the sort does the right thing zip =<< -- monad & applicative instances for functions are both insane, see above. -- everything below this line is the function which takes the input list -- and generates the _first_ argument to zip. The input list is used _again_ -- as the second argument. -- furthermore, using =<< is great because it has the same infixness as <<<, see above biconcat . partition isPrime -- primes to the left! . enumFromTo 1 -- all the numbers . length {- MCCOMMENT === 1. === This probably passes all tests given a large amount of time, right? bogodecrypt :: String -> String bogodecrypt = fromJust <<< lookup <*> (encrypt &&& id & map) . permutations === 2. === **Please don't give me credit for this suggestion**, it was pointed out to me by someone else who's not participating in this course (hey g.!) I'm assuming we can't change the encrypt signature since that's the stance the ÜL has taken previously, and I don't think it should be allowed after the exercise is published. But that's just my 2¢. So: if encrypt's sisgnature may be changed to the more general Ord a => [a] -> [a], one can change decrypt's usage of "biconcat . partition isPrime" to "encrypt" and save 3 tokens in decrypt without a performance penalty. Luckily, this result is no better than the equally-token-good bogodecrypt solution shown above, and I can't imagine you'd count this solution without counting bogodecrypt, right? encrypt'' :: Ord a => [a] -> [a] encrypt'' = map snd . biconcat . partition fst . zip (isPrime <$> enumFrom 1) decrypt'' :: Ord a => [a] -> [a] decrypt'' = map snd <<< sort <<< zip =<< encrypt'' . enumFromTo 1 . length -} {-TTEW-}