From 205dcb21ae2355b34db667ba33191b4d48834085 Mon Sep 17 00:00:00 2001 From: Andrea Ciceri Date: Mon, 4 Nov 2024 13:42:09 +0100 Subject: [PATCH] Things --- flake.lock | 58 ++++++++++++++++++++ flake.nix | 20 +++++++ src/ApplicativeChapter.hs | 48 +++++++++++++++++ src/FunctorChapter.hs | 110 ++++++++++++++++++++++++++++++++++++++ typeclassopedia.cabal | 106 ++++++++++++++++++++++++++++++++++++ 5 files changed, 342 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 src/ApplicativeChapter.hs create mode 100644 src/FunctorChapter.hs create mode 100644 typeclassopedia.cabal diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..949cd41 --- /dev/null +++ b/flake.lock @@ -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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..ace97db --- /dev/null +++ b/flake.nix @@ -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 + ]; + }; + }; + }; +} diff --git a/src/ApplicativeChapter.hs b/src/ApplicativeChapter.hs new file mode 100644 index 0000000..e323001 --- /dev/null +++ b/src/ApplicativeChapter.hs @@ -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) diff --git a/src/FunctorChapter.hs b/src/FunctorChapter.hs new file mode 100644 index 0000000..e1f7fc8 --- /dev/null +++ b/src/FunctorChapter.hs @@ -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 diff --git a/typeclassopedia.cabal b/typeclassopedia.cabal new file mode 100644 index 0000000..d67d3f6 --- /dev/null +++ b/typeclassopedia.cabal @@ -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