2
\$\begingroup\$

Below is my solution for the CTFP chapter 4 challenges which essentially involves composing partial functions (that don't have defined outputs for all possible inputs i.e. returning a Maybe).

The challenge is to implement composition, identity(to satisfy category requirements) and try it out with 2 partial functions. As I'm relatively new to Haskell, I was hoping to get a general code review with suggestions on better idioms and testing I could follow. Link to Code

import Test.HUnit

module Main where

-- Given
safeRoot :: Double -> Maybe Double
safeRoot x 
  | x < 0     = Nothing
  | otherwise = Just (sqrt x)

-- Q1: Identity and composition
partialFnId :: a -> Maybe a
partialFnId x = Just x

partialFnCompose :: (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)
partialFnCompose g f = \x -> case (f x) of
                          Just value -> g value
                          Nothing -> Nothing

-- Testing Q1
testPartialFnMeetsCategoryRequirements1 = TestCase $ assertEqual "Id should pass through inputs" (Just 3) (partialFnId 3)
testPartialFnMeetsCategoryRequirements2 = TestCase $ assertEqual "Composition with identity is noop(1)" (Just 2.0) ((partialFnCompose partialFnId safeRoot) 4)
testPartialFnMeetsCategoryRequirements3 = TestCase $ assertEqual "Composition with identity is noop(2)" (Just 2.0) ((partialFnCompose safeRoot partialFnId) 4)

-- Q2: Implement safeReciprocal
safeReciprocal :: Double -> Maybe Double
safeReciprocal x
  | x == 0    = Nothing
  | otherwise = Just (1 / x)

-- Q3: Implement safeRootReciprocal via composing the above 2.
safeRootReciprocal :: Double -> Maybe Double
safeRootReciprocal = partialFnCompose safeRoot safeReciprocal

-- Testing Q3
testSafeRootReciprocal1 = TestCase $ assertEqual "Provides root of reciprocal for valid inputs" (Just 2.0) (safeRootReciprocal 0.25)
testSafeRootReciprocal2 = TestCase $ assertEqual "Provides Nothing on invalid inputs(1)" Nothing (safeRootReciprocal 0.0)
testSafeRootReciprocal3 = TestCase $ assertEqual "Provides Nothing on invalid inputs(2)" Nothing (safeRootReciprocal (-0.25))

main = do
  runTestTT $ TestList [testPartialFnMeetsCategoryRequirements1,
                        testPartialFnMeetsCategoryRequirements2,
                        testPartialFnMeetsCategoryRequirements3,
                        testSafeRootReciprocal1,
                        testSafeRootReciprocal2,
                        testSafeRootReciprocal3]
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.