Is there an easier way to write this function and only using prelude from Haskell?

Viewed 136

So I'm pretty new to Haskell, and are trying to solve an assignment, I've solved it, but I'm wondering if there is an easier or prettier way to make a function do the same as my wordChange. I'm trying to only use what is already in prelude.

dictionaryChecker _ [] = False
dictionaryChecker word (x:xs) = if elem word (snd x) then True else dictionaryChecker word xs

wordChange :: String -> String 
wordChange str = unwords (map (\s -> if length (translate s) > 0 then (translate s) 
else if (dictionaryChecker s dictionary) then concat (replicate (length s) "*")
else s) (words str))

translate :: String -> String 
translate str = contains str dictionary

contains _ [] = ""
contains str (x:xs) = if elem str (snd x) then fst x else contains str xs
3 Answers

I'd suggest to use the lookup function from Prelude, which takes a key and a list of tuples (a.k.a a dictionary) and returns Maybe value. This simplfies your function a lot. Also, if changeWord uses a dictionary, it should be explicit instead of using a global variable. Below, a partial solution: since it is an assignment I think you should try to complete it ;)

changeWord :: [(String, String)] -> String -> String
changeWord dic s = unwords $ substitute ws
  where -- ws is just the list of words s has  
        ws = words s
        -- the function substitute does the word changing recursively. Try to complete it
        substitute []     = []
        substitute (x:xs) = 
         case lookup x dic of -- look for x in the dictionary and returns the value if found
           Nothing -> undefined --complete
           Just y  -> undefined --complete

An obfuscated answer: earn a gold star from your professor if you can explain how it works, and be accused of copying from the internet if you can't:

wordChange :: [(String, String)] -> String -> String
wordChange dict = unwords . map (foldr const <*> (`lookup` dict)) . words

Your dictionaryChecker is in essence an any :: Foldable f => (a -> Bool) -> f a -> Bool with elem word . snd as condition:

dictionaryChecker :: (Foldable f, Foldable g, Eq a) => a -> f (b, g a) -> Bool
dictionaryChecker word = any (elem word . snd)

as for a translate, we can work with a section of an infix operator [Haskell-wiki] to make a point-free function:

translate :: String -> String 
translate = (`contains` dictionary)

and for contains we can work with a foldr :: Foldable f => (a -> b -> b) -> b -> f a -> b

contains :: (Foldable f, Foldable g, Eq a) => a -> f (String, g a) -> String
contains str = foldr (\x y -> if … then … else …) ""

I leave implementing the … parts as an exercise.

Related