I wrote a simple program, that will make a string 'noisy' if the clipboard contains one. What disappoints me, is that I should manually check what I got from getClipboardString — in the Nothing case, we simply return from program, otherwise we modify the string. Is there a better way to do this kind of check?

import Data.Char (toUpper)
import System.Random (randomIO)
import System.Clipboard (setClipboardString, getClipboardString)
import Control.Monad (join)

main :: IO ()
main = do 
 join $ fmap (test doNoise) getClipboardString
 test :: (String -> IO ()) -> (Maybe String) -> IO ()
 test _ Nothing = return ()
 test f (Just s) = f s

 doNoise :: String -> IO ()
 doNoise s = do
  capsed <- (sequence $ map randCap s)
  setClipboardString capsed

 randCap :: Char -> IO Char
 randCap x = fmap ($ x) $ fmap choice (randomIO :: IO Bool)

 choice :: Bool -> (Char -> Char)
 choice x = if x then toUpper else id
main :: IO ()
main = traverse_ doNoise =<< getClipboardString where
 doNoise = setClipboardString <=< traverse randCap
 randCap x = bool id toUpper <$> (randomIO :: IO Bool) <*> pure x

Edit: Each change was arrived at through pattern-matching from my experience; compact code is usually easier to work with further. Looking at this again makes me think there ought to be a more lensy solution, one that fuses getting and setting, and indeed:

main = modifyClipboardString =<<
  zipWith (bool id toUpper) <$> getRandoms

We are fortunate to not actually need side effects depending on clipboard contents, but if we did, I would recommend writing a monadic variant of modifyClipboardString.

  • 2
    \$\begingroup\$ That's a compact solution :) Could you elaborate how you got to this and how it's better than the original code? \$\endgroup\$ – dfhwze Jun 11 '19 at 19:26
  • 4
    \$\begingroup\$ You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and why it is better than the original) so that the author and other readers can learn from your thought process. Please read Why are alternative solutions not welcome? \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Jun 11 '19 at 19:26
  • \$\begingroup\$ Some thoughts that I have: first, that I should use hoogle more thoroughly (I didn't know of traverse, traverse_ and bool); second, that I should read my code more closely, because I missed join $ fmap == (=<<). Anyway, elegant solution, will upvote later, not enough rep right now \$\endgroup\$ – Stuthedian Jun 12 '19 at 5:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.