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.

Cool to see you code, thanks!

ReplyDeleteTo 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)

Thanks Petter.

ReplyDeleteNice 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

Hi again Manuel

ReplyDeleteMaybe 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)

Hi Petter

ReplyDeleteYes, nil would be probably much better than an exception.

Best regards,

Manuel