[Haskell-beginners] Simplifying code
Krzysztof Skrzętnicki
gtener at gmail.com
Tue Feb 9 16:17:49 EST 2010
Hi
A few remarks about your code:
1. 'String' is a type synonym for [Char]. It makes types like [[Char]]
more readable (at least for me).
2. There is something imperative in the way you code: I think you rely
too much on numbers as iterators. You don't have to use numbers to
drive the program control flow. Examples:
main = do
filename <- getArgs
wordlist <- readFile $ filename !! 0
Why not:
main = do
(filename:_) <- getArgs
wordlist <- readFile filename
Or:
main = do
filename <- head <$> getArgs
wordlist <- readFile filename
Another example:
generateAll :: String -> [String]
generateAll word = g lea $ mutateWords word
where g 0 words = words
g n words = g (n - 1) (nub $ words >>= mutateWords )
lea = length leata
The 'g' function can be rewritten to get rid of the index number.
Here is what I got:
-- https://mail.google.com/mail/#inbox/126b45c29341640f
import System.Environment ( getArgs )
import Control.Applicative ( (<$>) )
import Data.Set (Set)
import qualified Data.Set as Set
---CONFIG section
type Rule = (Char,Char)
infixl 1 ==>
a ==> b = (a, b)
rules :: [Rule]
rules = ['s' ==> '$',
't' ==> '+',
'l' ==> '|',
'o' ==> '0',
'e' ==> '3',
'a' ==> '@',
'v' ==> '^']
nubOrd :: (Ord a) => [a] -> [a]
nubOrd = Set.toList . Set.fromList
singleton x = [x]
-- CORE PART
-- we mutate all words, rule at a time. If we run out of rules, we finish.
mutateWords :: [Rule] -> String -> [String]
mutateWords rules word = foldr (\r acc -> nubOrd (concatMap (applyRule
r) acc)) (singleton word) rules
-- apply one rule to one word. the result is a list of words.
applyRule :: Rule -> String -> [String]
applyRule (old,new) wrd = aux wrd where
aux [] = [[]]
-- we may or may not apply our rule here.
aux (c:cs) | c == old = [ c':suf | suf <- aux cs, c' <- [old,new] ]
| otherwise = [ c :suf | suf <- aux cs ]
main = do
(filename:_) <- getArgs
wordlist <- words <$> readFile filename
let mutated = concatMap (mutateWords rules) wordlist
mapM_ putStrLn mutated
Best regards
Krzysztof Skrzętnicki
On Tue, Feb 9, 2010 at 21:11, edgar klerks <edgar.klerks at gmail.com> wrote:
> Hi All,
>
> I wrote a program which permutates a list words with some rules. For example
> if I feed it a list like:
>
> banana
> waterloo
> vraag
>
> It gives back the list:
>
> banana
> b at nana
> ban at na
> b at n@na
> banan@
> b at nan@
> ban at n@
> b at n@n@
> waterloo
> wa+erloo
> water|oo
> waterl0o
> etc
>
> However I have the feeling I am doing things to complicated. I am still a
> beginner. Would someone like to help me simplify somethings. If you think
> this is inappropriate please state also. I am not offended then. I
> understand you are offering your spare time to help me.
>
> The first thing I don't get is this. I recognize some things could be
> rewritten with a bind operator (because of the concat $ fmap), but I am
> puzzled how:
>
> mutateWords :: [Char] -> [[Char]]
> mutateWords word = nub.concat $ fmap snd <$> fmap unzip <$> ( foldr(\x z ->
> let char = snd x
> nm = number word
> lst = fst x
> in (insertAt char nm <$> lst) : z
> ) [[]] $ mw word )
>
>
>
>
> Here is the full code:
>
>
> import Data.List
> import System
> import System.IO
> import Control.Applicative
>
>
> ---CONFIG section
>
> leat = ['s' ==> '$', 't' ==> '+', 'l' ==> '|', 'o' ==> '0','e' ==> '3', 'a'
> ==> '@', 'v' ==> '^']
>
> leata = fst.unzip $ leat
> leatb = snd.unzip $ leat
>
> -- Perl like assoc lists
> infixl 1 ==>
> a ==> b = (a, b)
>
>
> -- Flipped fmap sometimes nicer
> infixl 4 <$$>
>
> xs <$$> f = f <$> xs
>
>
> -- first I need to find the positions of the mutatable charachters.
> findPositions :: [Char] -> [[Int]]
> findPositions xs = take (length index) $ index <*> [xs]
> where index = elemIndices <$> leata
>
> -- And generate all subsequences
> findSubSeq :: [Char] -> [[[Int]]]
> findSubSeq = fmap subsequences <$> findPositions
>
>
> -- Only change elements which needs to be changed
> insertAt :: Char -> [(Int, Char)] -> [Int] -> [(Int,Char)]
> insertAt c xs ps = xs <$$> (\x ->
> if (fst x) `elem` ps
> then (fst x , c)
> else x
> )
> -- Couples character to mutable positions
> mw word = (findSubSeq word) `zip` leatb
>
> number = zip [0..]
>
> mutateWords :: [Char] -> [[Char]]
> mutateWords word = nub.concat $ fmap snd <$> fmap unzip <$> ( foldr(\x z ->
> let char = snd x
> nm = number word
> lst = fst x
> in (insertAt char nm <$> lst) : z
> ) [[]] $ mw word )
>
> generateAll :: [Char] -> [[Char]]
> generateAll word = g lea $ mutateWords word
> where g 0 words = words
> g n words = g (n - 1) (nub $ words >>= mutateWords )
> lea = length leata
> main = do
> filename <- getArgs
> wordlist <- readFile $ filename !! 0
> let a = (words wordlist) >>= generateAll
> mapM_ putStrLn a
>
> --
> Flatliner ICT Service,
> Email: Edgar.klerks at gmail.com,
> Tel: +31727851429
> Fax: +31848363080
> Skype: edgar.klerks
> Website: flatlinerict.nl
> Adres: Koelmalaan 258,
> 1813JD, Alkmaar
> Nederland
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
More information about the Beginners
mailing list