DEV Community

loading...

Discussion on: Daily Challenge #11 - Cubic Numbers

Collapse
deciduously profile image
Ben Lovy

Haskell:

import Data.Bool (bool)
import Data.List (intercalate)
import Data.List.Split (chunksOf, splitOn)
import Data.Maybe (isJust, fromJust)
import Text.Read (readMaybe)

failString :: String
failString = "Unlucky"

-- e.g. 153 becomes [1,5,3]
intoDigits :: Int -> [Int]
intoDigits 0 = []
intoDigits n = intoDigits (div n 10) ++ [mod n 10]

-- e.g [1,5,3] becomes 153
fromDigits :: [Int] -> Int
fromDigits = foldl addDigit 0
   where addDigit num d = 10 * num + d

-- Primary
-- Ideally, this'd have returned a Maybe String, but spec and all
isCubic :: Int -> String
isCubic n =
    let
        cubes = map (^3) $ intoDigits n
    in
        bool (failString) (show n) (length cubes <= 3 && (sum cubes) == n)

-- Secondary
showCubes :: String -> String
showCubes s =
    let
        maybeDigits = filter (isJust) $ map (\s -> readMaybe s :: Maybe Int) $ words s
        splitLongerThanThrees = map fromDigits $ concat $ map (chunksOf 3) $ map intoDigits $ map fromJust $ maybeDigits
        justCubes = filter (/= failString) $ map isCubic splitLongerThanThrees
    in
        bool (failString) (intercalate " " justCubes) (length justCubes > 0)

Note - splitting the long numbers up drops the zero from the success - it never even makes it to the check. I got it working either with the zero and no splitting or vice versa, and the fix for me at this point would be a special case to catch zero specifically. Which I should do, just not this second.

Edit: Problem is fixed by adding a the check when we map intoDigits over the input:

showCubes :: String -> String
showCubes s =
    let
        maybeDigits = filter (isJust) $ map (\s -> readMaybe s :: Maybe Int) $ words s
        splitLongerThanThrees = map fromDigits $ concat $ map (chunksOf 3) $ map intoDigitsCatchingZero $ map fromJust $ maybeDigits
        justCubes = filter (/= failString) $ map isCubic splitLongerThanThrees
    in
        bool (failString) (intercalate " " justCubes) (length justCubes > 0)
    where
        -- Prevents it from becoming []
        intoDigitsCatchingZero n = if n == 0 then [0] else intoDigits n

This problem happened because my implementation of intoDigits is recursive and requires a base case (0) that returns an empty list. Just gotta sidestep it in that one special instance. Could have also inserted a check in the let binding of isCubic but either way I coudln't figure out how to not have to check for it specifically. Now produces correct output, at least.

Collapse
coreyja profile image
Corey Alexander

Ideally, this'd have returned a Maybe String, but spec and all

Spec be damned, my version just returns a bool