This commit is contained in:
Andrea Ciceri 2024-11-04 13:42:09 +01:00
commit 205dcb21ae
Signed by: aciceri
SSH key fingerprint: SHA256:/AagBweyV4Hlfg9u092n8hbHwD5fcB6A3qhDiDA65Rg
5 changed files with 342 additions and 0 deletions

58
flake.lock generated Normal file
View file

@ -0,0 +1,58 @@
{
"nodes": {
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1727826117,
"narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1729880355,
"narHash": "sha256-RP+OQ6koQQLX5nw0NmcDrzvGL8HDLnyXt/jHhL1jwjM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18536bf04cd71abd345f9579158841376fdd0c5a",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1727825735,
"narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

20
flake.nix Normal file
View file

@ -0,0 +1,20 @@
{
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
systems = ["x86_64-linux"];
perSystem = {pkgs, ...}: {
devShells.default = pkgs.mkShell {
packages = with pkgs; [
cabal-install
ghc
haskell-language-server
];
};
};
};
}

48
src/ApplicativeChapter.hs Normal file
View file

@ -0,0 +1,48 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE InstanceSigs #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
module ApplicativeChapter () where
import Data.Function (const)
import GHC.Base ( id, Functor(..) )
import Data.Maybe (Maybe(..))
import Data.Function (($))
import Data.List (zipWith)
liftA2 :: ApplicativeChapter.Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
class Functor f => Applicative f where
pure :: a -> f a
infixl 4 <*>, *>
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
a1 *> a2 = (id <$ a1) <*> a2
(<*) :: f a -> f b -> f a
(<*) = liftA2 const
-- ??
-- Maybe is Applicative
instance Applicative Maybe where
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
(<*>) Nothing _ = Nothing
(<*>) (Just f) x = fmap f x
pure :: a -> Maybe a
pure = Just
-- List can be Applicative in 2 different ways
newtype ZipList a = ZipList { getZipList :: [a] }
instance Applicative ZipList where
pure :: a -> ZipList a
pure a = ZipList [a]
(<*>) :: ZipList (a -> b) -> ZipList a -> ZipList b
(ZipList gs) <*> (ZipList xs) = ZipList (zipWith ($) gs xs)

110
src/FunctorChapter.hs Normal file
View file

@ -0,0 +1,110 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE InstanceSigs #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
module FunctorChapter () where
import Data.Either (Either(..))
import Data.Function (($))
import Data.Int
import Data.Maybe ( Maybe, Maybe(..) )
const :: a -> b -> a
const a _ = a
class Functor f where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
{-# MINIMAL fmap #-}
(<$) a = fmap (const a)
-- 1
instance Functor (Either e) where
fmap :: (a -> b) -> Either e a -> Either e b
fmap f (Right ex) = Right $ f ex
fmap _ (Left x) = Left x
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) fbc fab x = fbc (fab x)
-- 1bis
instance Functor ((->) e) where
fmap :: (a -> b) -> (e -> a) -> (e -> b)
fmap fab fea = fab . fea
-- 2
instance Functor ((,) e) where
fmap :: (a -> b) -> (e, a) -> (e, b)
fmap f (e, bx) = (e, f bx)
data Pair a = Pair a a
instance Functor Pair where
fmap :: (a -> b) -> Pair a -> Pair b
fmap f (Pair ax ay) = Pair (f ax) (f ay)
-- Differences: Pair is a concrete type while ((,) e) isn't
-- Moreover both the wrapped values in Pair have the same type
-- and we have to wrap both if we want to return a Pair b
-- Instead for ((,) e) we don't know anything about e so we
-- cannot apply any function to it
data ITree a = Leaf (Int -> a)
| Node [ITree a]
-- 3
instance Functor [] where
fmap :: (a -> b) -> [] a -> [] b
fmap fab (x:xs) = fab x : fmap fab xs
fmap _ [] = []
instance Functor ITree where
fmap :: (a -> b) -> ITree a -> ITree b
fmap fab (Leaf fia) = Leaf $ fab . fia
fmap fab (Node ts) = Node (fmap (fmap fab) ts)
-- 4 ???
-- data Foo a = Foo
-- instance Functor Foo where
-- fmap :: (b -> c) -> Foo b -> Foo c
-- fmap fbc (Foo) = Foo
-- 5
newtype ListMaybe a = ListMaybe [Maybe a]
instance Functor Maybe where
fmap :: (a -> b) -> Maybe a -> Maybe b
fmap _ Nothing = Nothing
fmap fab (Just a) = Just $ fab a
instance Functor ListMaybe where
fmap :: (a -> b) -> ListMaybe a -> ListMaybe b
fmap fab (ListMaybe ms) = ListMaybe (fmap (fmap fab) ms)
-- 1
data Maybe' a = Just' a | Nothing'
instance Functor Maybe' where
fmap :: (a -> b) -> Maybe' a -> Maybe' b
fmap _ _ = Nothing'
-- fmap id = \x -> Nothing' != id
-- fmap f . fmap g = \x -> Nothing' = fmap (f . g)
-- 2
-- (evilFmap id) [1] = [1 1]
-- then evilFmap id != id
-- fmap id x:xs =
-- (id x):(id x):(fmap id xs) = # function application
-- x:x:(fmap id xs) = # associativity
-- x:( x:(fmap id xs) ) = # definition (list, well defined Functor []): fmap id xs = x: fmap id xs
-- x:( fmap id (x:xs) ) =
-- x:( id (x:xs) ) = # identity law substitution (fmap id = id)
-- (x:) . (id $ (:) x xs) = # rewrite using composition (.)
-- (x:) . id . (x:) xs = # rewrite using composition (.)
-- (x:) . id . (x:) = # eta reduction
-- != id

106
typeclassopedia.cabal Normal file
View file

@ -0,0 +1,106 @@
cabal-version: 3.0
-- The cabal-version field refers to the version of the .cabal specification,
-- and can be different from the cabal-install (the tool) version and the
-- Cabal (the library) version you are using. As such, the Cabal (the library)
-- version used must be equal or greater than the version stated in this field.
-- Starting from the specification version 2.2, the cabal-version field must be
-- the first thing in the cabal file.
-- Initial package description 'typeclassopedia' generated by
-- 'cabal init'. For further documentation, see:
-- http://haskell.org/cabal/users-guide/
--
-- The name of the package.
name: typeclassopedia
-- The package version.
-- See the Haskell package versioning policy (PVP) for standards
-- guiding when and how versions should be incremented.
-- https://pvp.haskell.org
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0
-- A short (one-line) description of the package.
-- synopsis:
-- A longer description of the package.
-- description:
-- URL for the project homepage or repository.
homepage: https://github.com/aciceri/typeclassoopedia
-- The license under which the package is released.
license: GPL-3.0-only
-- The file containing the license text.
license-file: LICENSE
-- The package author(s).
author: Andrea Ciceri
-- An email address to which users can send suggestions, bug reports, and patches.
maintainer: andrea.ciceri@autistici.org
-- A copyright notice.
-- copyright:
build-type: Simple
-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.
extra-doc-files: CHANGELOG.md
-- Extra source files to be distributed with the package, such as examples, or a tutorial module.
-- extra-source-files:
common warnings
ghc-options: -Wall
library
-- Import common warning flags.
import: warnings
-- Modules exported by the library.
exposed-modules: FunctorChapter, ApplicativeChapter
-- Modules included in this library but not exported.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
-- Other library packages from which modules are imported.
build-depends: base ^>=4.18.2.1
-- Directories containing source files.
hs-source-dirs: src
-- Base language which the package is written in.
default-language: Haskell2010
test-suite typeclassopedia-test
-- Import common warning flags.
import: warnings
-- Base language which the package is written in.
default-language: Haskell2010
-- Modules included in this executable, other than Main.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
-- The interface type and version of the test suite.
type: exitcode-stdio-1.0
-- Directories containing source files.
hs-source-dirs: test
-- The entrypoint to the test suite.
main-is: Main.hs
-- Test dependencies.
build-depends:
base ^>=4.18.2.1,
typeclassopedia