{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE InstanceSigs #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use lambda-case" #-}
-- | Notes taken by Julija Mikeliūnaitė
module Lessons.Lesson08 where

import Data.Char
import Control.Applicative

-- | Monad is the most powerful class. 
-- Bind method (>>=) gives the illusion of sequential computation.
--
-- Functors ignore the order of execution.
--
-- | Minimal implementation of a functor:
-- fmap :: Functor f => (a -> b) -> f a -> f b
-- It takes a pure function (which takes a and returns b), a functor of a, and returns a functor of b.

-- | The function was applied to every element of the list.
--
-- >>> fl
-- [5,4]
fl :: [Int]
fl :: [Int]
fl = (String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String
"labas", String
"medi"]

-- | If the list is empty, the result is also an empty list.
--
-- >>> fm
-- Nothing
fm :: Maybe Integer
fm :: Maybe Integer
fm = (Integer -> Integer) -> Maybe Integer -> Maybe Integer
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+Integer
1) Maybe Integer
forall a. Maybe a
Nothing

-- >>> fe
-- Right 42
fe :: Either String Integer
fe :: Either String Integer
fe = (Integer -> Integer)
-> Either String Integer -> Either String Integer
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+Integer
1) (Either String Integer -> Either String Integer)
-> Either String Integer -> Either String Integer
forall a b. (a -> b) -> a -> b
$ Integer -> Either String Integer
forall a b. b -> Either a b
Right Integer
41

-- | The left value is considered a "bad" value.
--
-- >>> fe'
-- Left 41
fe' :: Either Integer Integer
fe' :: Either Integer Integer
fe' = (Integer -> Integer)
-> Either Integer Integer -> Either Integer Integer
forall a b. (a -> b) -> Either Integer a -> Either Integer b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+Integer
1) (Either Integer Integer -> Either Integer Integer)
-> Either Integer Integer -> Either Integer Integer
forall a b. (a -> b) -> a -> b
$ Integer -> Either Integer Integer
forall a b. a -> Either a b
Left Integer
41

-- | Takes an input and returns the value with "!"" in the end. Returned type is IO String. IO is a type which presents computations which originate in the external world.
--
fio :: IO String
fio :: IO String
fio = (String -> String) -> IO String -> IO String
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\String
a -> String
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"!") IO String
getLine

-- | Applicative functor is between functor and monad.

-- | pure is pretty much the same as return:
-- pure :: Applicative f => a -> f a
-- return :: Monad m => a -> m a
--
-- >>> p
-- [5]
p :: [Integer]
p :: [Integer]
p = Integer -> [Integer]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
5

-- | Signature <*>, sometimes called "spaceship".
-- (<*>) :: Applicative f => (a -> b) -> f a -> f b
-- It is similar to fmap, but instead of a Functor, it uses an Applicative.

-- | Signature <$> is synonymous with fmap.
--
-- >>> am
-- Just 46
am :: Maybe Integer
am :: Maybe Integer
am = Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(+) (Integer -> Integer -> Integer)
-> Maybe Integer -> Maybe (Integer -> Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
5) Maybe (Integer -> Integer) -> Maybe Integer -> Maybe Integer
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
41)

-- >>> am'
-- Just 47
am' :: Maybe Integer
am' :: Maybe Integer
am' = (\Integer
a Integer
b Integer
c -> Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
c) (Integer -> Integer -> Integer -> Integer)
-> Maybe Integer -> Maybe (Integer -> Integer -> Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
5) Maybe (Integer -> Integer -> Integer)
-> Maybe Integer -> Maybe (Integer -> Integer)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
41) Maybe (Integer -> Integer) -> Maybe Integer -> Maybe Integer
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
1)

-- >>> am''
-- Nothing
am'' :: Maybe Integer
am'' :: Maybe Integer
am'' = (\Integer
a Integer
b Integer
c -> Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
c) (Integer -> Integer -> Integer -> Integer)
-> Maybe Integer -> Maybe (Integer -> Integer -> Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
5) Maybe (Integer -> Integer -> Integer)
-> Maybe Integer -> Maybe (Integer -> Integer)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Integer
forall a. Maybe a
Nothing Maybe (Integer -> Integer) -> Maybe Integer -> Maybe Integer
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
1)

-- >>> :t (\a b c -> a + b + c) <$> (Just 5) <*> Nothing
-- (\a b c -> a + b + c) <$> (Just 5) <*> Nothing :: Num a => Maybe (a -> a)

-- >>> :t (\a b c -> a + b + c) <$> (Just 5)
-- (\a b c -> a + b + c) <$> (Just 5) :: Num a => Maybe (a -> a -> a)

-- >>> :t fmap (\a b c -> a + b + c)
-- fmap (\a b c -> a + b + c) :: (Functor f, Num a) => f a -> f (a -> a -> a)

-- | Sources of values are completely independent, computed in parallel.
--
-- >>> al
-- [2,3,3,4,4,5]
al :: [Integer]
al :: [Integer]
al = Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(+) (Integer -> Integer -> Integer)
-> [Integer] -> [Integer -> Integer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Integer
1,Integer
2,Integer
3] [Integer -> Integer] -> [Integer] -> [Integer]
forall a b. [a -> b] -> [a] -> [b]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Integer
1, Integer
2]

-- | Sources of values depend on values that are above, line-by-line.
--
-- >>> ml
-- [2,3,3,4,4,5]
ml :: [Integer]
ml :: [Integer]
ml = do
    Integer
a <- [Integer
1,Integer
2,Integer
3]
    Integer
b <- [Integer
1, Integer
2]
    Integer -> [Integer]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> [Integer]) -> Integer -> [Integer]
forall a b. (a -> b) -> a -> b
$ Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
b

-- | newtype is used if ADT has a single constructor.
--
newtype Parser a = Parser {
    forall a. Parser a -> String -> Either String (a, String)
runParser :: String -> Either String (a, String)
}

-- | If a number is parsed, then it returns Left value.
--
-- >>> runParser parseLetter "skfhsdk"
-- Right ('s',"kfhsdk")
parseLetter :: Parser Char
parseLetter :: Parser Char
parseLetter = (String -> Either String (Char, String)) -> Parser Char
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (Char, String)) -> Parser Char)
-> (String -> Either String (Char, String)) -> Parser Char
forall a b. (a -> b) -> a -> b
$ \case 
    [] -> String -> Either String (Char, String)
forall a b. a -> Either a b
Left String
"A letter is expected but got empty input"
    (Char
h:String
t) -> if Char -> Bool
isAlpha Char
h
        then (Char, String) -> Either String (Char, String)
forall a b. b -> Either a b
Right (Char
h, String
t)
        else String -> Either String (Char, String)
forall a b. a -> Either a b
Left (String -> Either String (Char, String))
-> String -> Either String (Char, String)
forall a b. (a -> b) -> a -> b
$ String
"A letter is expected, but got " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
h]

instance Functor Parser where
  fmap :: (a -> b) -> Parser a -> Parser b
  fmap :: forall a b. (a -> b) -> Parser a -> Parser b
fmap a -> b
f Parser a
functor = (String -> Either String (b, String)) -> Parser b
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (b, String)) -> Parser b)
-> (String -> Either String (b, String)) -> Parser b
forall a b. (a -> b) -> a -> b
$ \String
input ->
    case Parser a -> String -> Either String (a, String)
forall a. Parser a -> String -> Either String (a, String)
runParser Parser a
functor String
input of
        Left String
e -> String -> Either String (b, String)
forall a b. a -> Either a b
Left String
e
        Right (a
v, String
r) -> (b, String) -> Either String (b, String)
forall a b. b -> Either a b
Right (a -> b
f a
v, String
r)

-- >>> runParser (fmap (\c -> [c,c]) parseLetter) "labas"
-- Right ("ll","abas")

instance Applicative Parser where
  pure :: a -> Parser a
  pure :: forall a. a -> Parser a
pure a
a = (String -> Either String (a, String)) -> Parser a
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (a, String)) -> Parser a)
-> (String -> Either String (a, String)) -> Parser a
forall a b. (a -> b) -> a -> b
$ \String
input -> (a, String) -> Either String (a, String)
forall a b. b -> Either a b
Right (a
a, String
input)
  (<*>) :: Parser (a -> b) -> Parser a -> Parser b
  Parser (a -> b)
af <*> :: forall a b. Parser (a -> b) -> Parser a -> Parser b
<*> Parser a
aa = (String -> Either String (b, String)) -> Parser b
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (b, String)) -> Parser b)
-> (String -> Either String (b, String)) -> Parser b
forall a b. (a -> b) -> a -> b
$ \String
input ->
    case Parser (a -> b) -> String -> Either String (a -> b, String)
forall a. Parser a -> String -> Either String (a, String)
runParser Parser (a -> b)
af String
input of
        Left String
e1 -> String -> Either String (b, String)
forall a b. a -> Either a b
Left String
e1
        Right (a -> b
f, String
r1) ->
            case Parser a -> String -> Either String (a, String)
forall a. Parser a -> String -> Either String (a, String)
runParser Parser a
aa String
r1 of
                Left String
e2 -> String -> Either String (b, String)
forall a b. a -> Either a b
Left String
e2
                Right (a
a, String
r2) -> (b, String) -> Either String (b, String)
forall a b. b -> Either a b
Right (a -> b
f a
a, String
r2)

-- >>> runParser threeLetters "labas"
-- Right ("lab","as")
threeLetters :: Parser String
threeLetters :: Parser String
threeLetters = (\Char
a Char
b Char
c -> [Char
a, Char
b, Char
c]) (Char -> Char -> Char -> String)
-> Parser Char -> Parser (Char -> Char -> String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Char
parseLetter Parser (Char -> Char -> String)
-> Parser Char -> Parser (Char -> String)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Char
parseLetter Parser (Char -> String) -> Parser Char -> Parser String
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Char
parseLetter

-- >>> (Just 5) <|> (Just 6)
-- Just 5
-- >>> Nothing <|> (Just 6)
-- Just 6

-- >>> [] <|> [] <|> [1,2,3]
-- [1,2,3]

-- | Signature <|>, sometimes called 'alternative'
-- 
instance Alternative Parser where
  empty :: Parser a
  empty :: forall a. Parser a
empty = (String -> Either String (a, String)) -> Parser a
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (a, String)) -> Parser a)
-> (String -> Either String (a, String)) -> Parser a
forall a b. (a -> b) -> a -> b
$ \String
_ -> String -> Either String (a, String)
forall a b. a -> Either a b
Left String
"No alternatives"
  (<|>) :: Parser a -> Parser a -> Parser a
  Parser a
p1 <|> :: forall a. Parser a -> Parser a -> Parser a
<|> Parser a
p2 = (String -> Either String (a, String)) -> Parser a
forall a. (String -> Either String (a, String)) -> Parser a
Parser ((String -> Either String (a, String)) -> Parser a)
-> (String -> Either String (a, String)) -> Parser a
forall a b. (a -> b) -> a -> b
$ \String
input ->
    case Parser a -> String -> Either String (a, String)
forall a. Parser a -> String -> Either String (a, String)
runParser Parser a
p1 String
input of
        Right (a, String)
r2 -> (a, String) -> Either String (a, String)
forall a b. b -> Either a b
Right (a, String)
r2
        Left String
e1 ->
            case Parser a -> String -> Either String (a, String)
forall a. Parser a -> String -> Either String (a, String)
runParser Parser a
p2 String
input of
                Right (a, String)
r2 -> (a, String) -> Either String (a, String)
forall a b. b -> Either a b
Right (a, String)
r2
                Left String
e2 -> String -> Either String (a, String)
forall a b. a -> Either a b
Left (String -> Either String (a, String))
-> String -> Either String (a, String)
forall a b. (a -> b) -> a -> b
$ String
e1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"; " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
e2 
-- Can't be tested yet since we only have one parser!

-- >>> runParser parseString "4123"
-- Right ("","4123")
-- >>> runParser parseString "asd4123"
-- Right ("asd","4123")
parseString :: Parser String
parseString :: Parser String
parseString = Parser Char -> Parser String
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Char
parseLetter

-- >>> runParser parseNonEmptyString "4123"
-- Left "A letter is expected, but got 4"
-- >>> runParser parseNonEmptyString "asd4123"
-- Right ("asd","4123")
parseNonEmptyString :: Parser String
parseNonEmptyString :: Parser String
parseNonEmptyString = Parser Char -> Parser String
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some Parser Char
parseLetter