Monday, July 13, 2015

Exercism: "Hexadecimal in Clojure"

I solved the Hexadecimal problem in Clojure.

As usual I extracted some helpers and played with partial and the thread last macro (->>) to try to make the solution more readable:

You can nitpick my solution here and/or see all the exercises I've done so far in this repository.

4 comments:

  1. Cool to see you code, thanks!

    To be a bit picky - I am not sure if it is correct to return 0 if the string is not valid hex? Zero is also a number.

    Below is my Haskell solution to this, solving it with the maybe-monad. Not sure what the canonical clojure way would be? Throwing an error, maybe?

    Cheers,

    Petter

    --

    import Data.Char
    import Data.Functor
    import Control.Applicative

    toDig :: Char -> Maybe Int
    toDig c
    | c >= 'a' && c <= 'f' = Just ((ord c) - 87)
    | c >= '0' && c <= '9' = Just ((ord c) - 48)
    | otherwise = Nothing

    toNumList :: [Char] -> [Maybe Int]
    toNumList = map (toDig . toLower)

    toNumRec :: [Maybe Int] -> Int -> Maybe Int -> Maybe Int
    toNumRec [] i acc = acc
    toNumRec (f:rest) i acc
    | f == Nothing = f
    | otherwise = let acc' = (+) <$> acc <*> (pure (*(16^i)) <*> f)
    in toNumRec rest (i+1) acc'

    toDec str = toNumRec (reverse (toNumList str)) 0 (Just 0)

    ReplyDelete
  2. Thanks Petter.

    Nice solution the Haskell one!

    I also found weird to return a zero in case of an invalid hex string.

    I did it jut to make the Exercism given tests pass, this one in particular:
    (deftest hex-to-int-invalid-hex
    (is (= 0 (hexadecimal/hex-to-int "carrot"))))

    I'm not sure which is the canonical Clojure way. I'm still a beginner. I guess I'd throw an IllegalArgumentException.

    Best regards,
    Manuel

    ReplyDelete
  3. Hi again Manuel

    Maybe the solution is as simpe as returning 'nil - in case you test would pass if you test this value?

    Here is a slightly shorter haskell version:

    import Data.Char
    import Data.Functor
    import Control.Applicative

    toDig :: Char -> Maybe Int
    toDig c
    | elem c ['a'..'f'] = Just ((ord c) - 87)
    | elem c ['0'..'9'] = Just ((ord c) - 48)
    | otherwise = Nothing

    toNumList :: [Char] -> [Maybe Int]
    toNumList = map (toDig . toLower)

    toNumRec :: [Maybe Int] -> Int -> Maybe Int -> Maybe Int
    toNumRec [] i acc = acc
    toNumRec (f:rest) i acc =
    let acc' = liftA2 (\acc f -> ((16^i)*f) + acc) acc f
    in toNumRec rest (i+1) acc'

    toDec str = toNumRec (reverse (toNumList str)) 0 (Just 0)

    ReplyDelete
  4. Hi Petter
    Yes, nil would be probably much better than an exception.
    Best regards,
    Manuel

    ReplyDelete