🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of BuilderNamedBob

BuilderNamedBob's solution

to Raindrops in the Haskell Track

Published at Apr 20 2021 · 0 comments
Test suite

Your task is to convert a number into a string that contains raindrop sounds corresponding to certain potential factors. A factor is a number that evenly divides into another number, leaving no remainder. The simplest way to test if a one number is a factor of another is to use the modulo operation.

The rules of raindrops are that if a given number:

  • has 3 as a factor, add 'Pling' to the result.
  • has 5 as a factor, add 'Plang' to the result.
  • has 7 as a factor, add 'Plong' to the result.
  • does not have any of 3, 5, or 7 as a factor, the result should be the digits of the number.


  • 28 has 7 as a factor, but not 3 or 5, so the result would be "Plong".
  • 30 has both 3 and 5 as factors, but not 7, so the result would be "PlingPlang".
  • 34 is not factored by 3, 5, or 7, so the result would be "34".


You need to implement the convert function that returns number converted to raindrop sound. You can use the provided signature if you are unsure about the types, but don't let it restrict your creativity:

convert :: Int -> String

This exercise works with textual data. For historical reasons, Haskell's String type is synonymous with [Char], a list of characters. For more efficient handling of textual data, the Text type can be used.

As an optional extension to this exercise, you can

import qualified Data.Text as T
import           Data.Text (Text)
  • You can now write e.g. convert :: Int -> Text and refer to Data.Text combinators as e.g. T.pack.
  • Look up the documentation for Data.Text,
  • You can then replace all occurrences of String with Text in Raindrops.hs:
convert :: Int -> Text

This part is entirely optional.

Getting Started

Please refer to the installation and learning help pages.

Running the tests

To run the test suite, execute the following command:

stack test

If you get an error message like this...

No .cabal file found in directory

You are probably running an old stack version and need to upgrade it.

Otherwise, if you get an error message like this...

No compiler found, expected minor version match with...
Try running "stack setup" to install the correct GHC...

Just do as it says and it will download and install the correct compiler version:

stack setup

Running GHCi

If you want to play with your solution in GHCi, just run the command:

stack ghci

Feedback, Issues, Pull Requests

The exercism/haskell repository on GitHub is the home for all of the Haskell exercises.

If you have feedback about an exercise, or want to help implementing a new one, head over there and create an issue. We'll do our best to help you!


A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. https://en.wikipedia.org/wiki/Fizz_buzz

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.


{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Foldable     (for_)
import Test.Hspec        (Spec, describe, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
import Data.String       (fromString)

import Raindrops (convert)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = describe "convert" $ for_ cases test

    test (number, expected) = it description assertion
        description = show number
        assertion   = convert number `shouldBe` fromString expected

    cases = [ (   1, "1"              )
            , (   3, "Pling"          )
            , (   5, "Plang"          )
            , (   7, "Plong"          )
            , (   6, "Pling"          )
            , (   8, "8"              )
            , (   9, "Pling"          )
            , (  10, "Plang"          )
            , (  14, "Plong"          )
            , (  15, "PlingPlang"     )
            , (  21, "PlingPlong"     )
            , (  25, "Plang"          )
            , (  27, "Pling"          )
            , (  35, "PlangPlong"     )
            , (  49, "Plong"          )
            , (  52, "52"             )
            , ( 105, "PlingPlangPlong")
            , (3125, "Plang"          ) ]

-- 4d356f447fcddd28b5dbf1df881bed95f26bba85
module Raindrops (convert) where

convert :: Int -> String
convert n = if or hasFactorList
            then concat [stringList !! x | x <- [0..2], hasFactorList !! x]
            else show n
        hasFactorList = hasFactors [3,5,7] n
        stringList = ["Pling","Plang","Plong"]

hasFactor :: Int -> Int -> Bool
hasFactor factor number = number `mod` factor == 0

hasFactors :: [Int] -> Int -> [Bool]
hasFactors factorList number = map (`hasFactor` number) factorList

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?