-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Abhijit Sarkar
committed
Dec 28, 2024
1 parent
1405e89
commit 4238c33
Showing
7 changed files
with
219 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
{-# LANGUAGE InstanceSigs #-} | ||
{-# LANGUAGE RebindableSyntax #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE NoImplicitPrelude #-} | ||
|
||
module Monad where | ||
|
||
import Applicative (Applicative) | ||
import qualified Applicative as A | ||
import Core | ||
import ExactlyOne (ExactlyOne (..)) | ||
import qualified ExactlyOne as EO | ||
import qualified Functor as F | ||
import List (List (..)) | ||
import qualified List as L | ||
import Optional (Optional (..)) | ||
import qualified Optional as O | ||
import qualified Prelude as P ((=<<)) | ||
|
||
-- | All instances of the `Monad` type-class must satisfy one law. This law | ||
-- is not checked by the compiler. This law is given as: | ||
-- | ||
-- * The law of associativity | ||
-- `∀f g x. g =<< (f =<< x) ≅ ((g =<<) . f) =<< x` | ||
class (Applicative f) => Monad f where | ||
-- Pronounced, bind. | ||
(=<<) :: (a -> f b) -> f a -> f b | ||
|
||
infixr 1 =<< | ||
|
||
-- | Binds a function on the ExactlyOne monad. | ||
-- | ||
-- >>> (\x -> ExactlyOne(x+1)) =<< ExactlyOne 2 | ||
-- ExactlyOne 3 | ||
instance Monad ExactlyOne where | ||
(=<<) :: (a -> ExactlyOne b) -> ExactlyOne a -> ExactlyOne b | ||
(=<<) = EO.bindExactlyOne | ||
|
||
-- | Binds a function on a List. | ||
-- | ||
-- >>> (\n -> n :. n :. Nil) =<< (1 :. 2 :. 3 :. Nil) | ||
-- [1,1,2,2,3,3] | ||
instance Monad List where | ||
(=<<) :: (a -> List b) -> List a -> List b | ||
(=<<) = L.flatMap | ||
|
||
-- | Binds a function on an Optional. | ||
-- | ||
-- >>> (\n -> Full (n + n)) =<< Full 7 | ||
-- Full 14 | ||
instance Monad Optional where | ||
(=<<) :: (a -> Optional b) -> Optional a -> Optional b | ||
(=<<) = O.bindOptional | ||
|
||
-- | Binds a function on the reader ((->) t). | ||
-- | ||
-- >>> ((*) =<< (+10)) 7 | ||
-- 119 | ||
instance Monad ((->) t) where | ||
(=<<) :: (a -> (->) t b) -> (->) t a -> (->) t b | ||
f =<< g = \x -> f (g x) x | ||
|
||
-- | Witness that all things with (=<<) and (<$>) also have (<*>). | ||
-- | ||
-- >>> ExactlyOne (+10) <**> ExactlyOne 8 | ||
-- ExactlyOne 18 | ||
-- | ||
-- >>> (+1) :. (*2) :. Nil <**> 1 :. 2 :. 3 :. Nil | ||
-- [2,3,4,2,4,6] | ||
-- | ||
-- >>> Full (+8) <**> Full 7 | ||
-- Full 15 | ||
-- | ||
-- >>> Empty <**> Full 7 | ||
-- Empty | ||
-- | ||
-- >>> Full (+8) <**> Empty | ||
-- Empty | ||
-- | ||
-- >>> ((+) <**> (+10)) 3 | ||
-- 16 | ||
-- | ||
-- >>> ((+) <**> (+5)) 3 | ||
-- 11 | ||
-- | ||
-- >>> ((+) <**> (+5)) 1 | ||
-- 7 | ||
-- | ||
-- >>> ((*) <**> (+10)) 3 | ||
-- 39 | ||
-- | ||
-- >>> ((*) <**> (+2)) 3 | ||
-- 15 | ||
(<**>) :: (Monad f) => f (a -> b) -> f a -> f b | ||
(<**>) = (A.<*>) | ||
|
||
infixl 4 <**> | ||
|
||
-- | Flattens a combined structure to a single structure. | ||
-- | ||
-- >>> join ((1 :. 2 :. 3 :. Nil) :. (1 :. 2 :. Nil) :. Nil) | ||
-- [1,2,3,1,2] | ||
-- | ||
-- >>> join (Full Empty) | ||
-- Empty | ||
-- | ||
-- >>> join (Full (Full 7)) | ||
-- Full 7 | ||
-- | ||
-- >>> join (+) 7 | ||
-- 14 | ||
join :: (Monad f) => f (f a) -> f a | ||
join = (=<<) id | ||
|
||
-- | Implement a flipped version of @(=<<)@, however, use only | ||
-- @join@ and @(<$>)@. | ||
-- Pronounced, bind flipped. | ||
-- | ||
-- >>> ((+10) >>= (*)) 7 | ||
-- 119 | ||
(>>=) :: (Monad f) => f a -> (a -> f b) -> f b | ||
a >>= f = join (f F.<$> a) | ||
|
||
infixl 1 >>= | ||
|
||
-- | Implement composition within the @Monad@ environment. | ||
-- Pronounced, kleisli composition. | ||
-- | ||
-- >>> ((\n -> n :. n :. Nil) <=< (\n -> n+1 :. n+2 :. Nil)) 1 | ||
-- [2,2,3,3] | ||
(<=<) :: (Monad f) => (b -> f c) -> (a -> f b) -> a -> f c | ||
f <=< g = \x -> f =<< g x | ||
|
||
infixr 1 <=< | ||
|
||
----------------------- | ||
-- SUPPORT LIBRARIES -- | ||
----------------------- | ||
|
||
instance Monad IO where | ||
(=<<) = | ||
(P.=<<) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
module MonadSpec (spec) where | ||
|
||
import ExactlyOne (ExactlyOne (..)) | ||
import List (List (..)) | ||
import qualified Monad as M | ||
import Optional (Optional (..)) | ||
import Test.Hspec | ||
|
||
spec :: Spec | ||
spec = do | ||
describe "(=<<)" $ do | ||
it "ExactlyOne" $ | ||
((\x -> ExactlyOne (x + 1)) M.=<< ExactlyOne 2) `shouldBe` ExactlyOne (3 :: Int) | ||
it "List" $ | ||
((\n -> n :. n :. Nil) M.=<< (1 :. 2 :. 3 :. Nil)) `shouldBe` ((1 :: Int) :. 1 :. 2 :. 2 :. 3 :. 3 :. Nil) | ||
it "Optional" $ | ||
((\n -> Full (n + n)) M.=<< Full 7) `shouldBe` Full (14 :: Int) | ||
it "(->)" $ | ||
((*) M.=<< (+ 10)) 7 `shouldBe` (119 :: Int) | ||
|
||
describe "<**>" $ do | ||
it "ExactlyOne" $ | ||
ExactlyOne (+ 10) M.<**> ExactlyOne 8 `shouldBe` ExactlyOne (18 :: Int) | ||
it "List" $ | ||
(+ 1) :. (* 2) :. Nil M.<**> 1 :. 2 :. 3 :. Nil `shouldBe` ((2 :: Int) :. 3 :. 4 :. 2 :. 4 :. 6 :. Nil) | ||
it "Optional" $ | ||
Full (+ 8) M.<**> Full 7 `shouldBe` Full (15 :: Int) | ||
it "Optional - empty function" $ | ||
Empty M.<**> Full (7 :: Int) `shouldBe` (Empty :: Optional Int) | ||
it "Optional - empty value" $ | ||
Full (+ 8) M.<**> Empty `shouldBe` (Empty :: Optional Int) | ||
it "(->) 1" $ | ||
((+) M.<**> (+ 10)) 3 `shouldBe` (16 :: Int) | ||
it "(->) 2" $ | ||
((+) M.<**> (+ 5)) 3 `shouldBe` (11 :: Int) | ||
it "(->) 3" $ | ||
((+) M.<**> (+ 5)) 1 `shouldBe` (7 :: Int) | ||
it "(->) 4" $ | ||
((*) M.<**> (+ 10)) 3 `shouldBe` (39 :: Int) | ||
it "(->) 5" $ | ||
((*) M.<**> (+ 2)) 3 `shouldBe` (15 :: Int) | ||
|
||
describe "join" $ do | ||
it "List" $ | ||
M.join ((1 :. 2 :. 3 :. Nil) :. (1 :. 2 :. Nil) :. Nil) `shouldBe` ((1 :: Int) :. 2 :. 3 :. 1 :. 2 :. Nil) | ||
it "Optional with Empty" $ | ||
M.join (Full Empty) `shouldBe` (Empty :: Optional Integer) | ||
it "Optional all Full" $ | ||
M.join (Full (Full 7)) `shouldBe` Full (7 :: Int) | ||
it "(->)" $ | ||
M.join (+) 7 `shouldBe` (14 :: Int) | ||
|
||
it "(>>=)" $ | ||
((+ 10) M.>>= (*)) 7 `shouldBe` (119 :: Int) | ||
|
||
it "kleislyComposition" $ | ||
((\n -> n :. n :. Nil) M.<=< (\n -> n + 1 :. n + 2 :. Nil)) 1 `shouldBe` ((2 :: Int) :. 2 :. 3 :. 3 :. Nil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters