Add free
This commit is contained in:
parent
8456714ab4
commit
05d04490e8
|
@ -9,6 +9,7 @@
|
|||
| [ecs](./ecs/) | Purescript-wrapper for [thi.ng/ecs](thi.ng/ecs) |
|
||||
| [existentials-blog](./existentials-blog) | Perhaps supposed to turn into a blog about existentials? |
|
||||
| [existentials](./existentials) | Experiment regarding the Church-encoding of existential types |
|
||||
| [free](./free/) | Experiments regarding free monads and interpreting algebras |
|
||||
| [gadts](./gadts) | Experiment regarding ways to encode GADTs in Purescript |
|
||||
| [lambda-calculus](./lambda-calculus) | Lambda calculus evaluator |
|
||||
| [lunarline](./lunarline) | Attempt at optimizing a functional language using compile-time partial evaluation |
|
||||
|
|
10
purescript/free/.gitignore
vendored
Normal file
10
purescript/free/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/bower_components/
|
||||
/node_modules/
|
||||
/.pulp-cache/
|
||||
/output/
|
||||
/generated-docs/
|
||||
/.psc-package/
|
||||
/.psc*
|
||||
/.purs*
|
||||
/.psa*
|
||||
/.spago
|
11
purescript/free/README.md
Normal file
11
purescript/free/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Free
|
||||
|
||||
My experiments with free monads and interpreting algebras.
|
||||
|
||||
## File structure
|
||||
|
||||
| File | Description |
|
||||
| -------------------------------- | -------------------------------------------------------- |
|
||||
| [Exists.purs](./src/Exists.purs) | Basic existential types |
|
||||
| [Lambda.purs](./src/Lambda.purs) | Function call algebra and interpreter using existentials |
|
||||
| [Math.purs](./src/Math.purs) | Addition & multiplication free monad and interpreter |
|
110
purescript/free/packages.dhall
Normal file
110
purescript/free/packages.dhall
Normal file
|
@ -0,0 +1,110 @@
|
|||
{-
|
||||
Welcome to your new Dhall package-set!
|
||||
|
||||
Below are instructions for how to edit this file for most use
|
||||
cases, so that you don't need to know Dhall to use it.
|
||||
|
||||
## Warning: Don't Move This Top-Level Comment!
|
||||
|
||||
Due to how `dhall format` currently works, this comment's
|
||||
instructions cannot appear near corresponding sections below
|
||||
because `dhall format` will delete the comment. However,
|
||||
it will not delete a top-level comment like this one.
|
||||
|
||||
## Use Cases
|
||||
|
||||
Most will want to do one or both of these options:
|
||||
1. Override/Patch a package's dependency
|
||||
2. Add a package not already in the default package set
|
||||
|
||||
This file will continue to work whether you use one or both options.
|
||||
Instructions for each option are explained below.
|
||||
|
||||
### Overriding/Patching a package
|
||||
|
||||
Purpose:
|
||||
- Change a package's dependency to a newer/older release than the
|
||||
default package set's release
|
||||
- Use your own modified version of some dependency that may
|
||||
include new API, changed API, removed API by
|
||||
using your custom git repo of the library rather than
|
||||
the package set's repo
|
||||
|
||||
Syntax:
|
||||
where `entityName` is one of the following:
|
||||
- dependencies
|
||||
- repo
|
||||
- version
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with packageName.entityName = "new value"
|
||||
-------------------------------
|
||||
|
||||
Example:
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with halogen.version = "master"
|
||||
with halogen.repo = "https://example.com/path/to/git/repo.git"
|
||||
|
||||
with halogen-vdom.version = "v4.0.0"
|
||||
-------------------------------
|
||||
|
||||
### Additions
|
||||
|
||||
Purpose:
|
||||
- Add packages that aren't already included in the default package set
|
||||
|
||||
Syntax:
|
||||
where `<version>` is:
|
||||
- a tag (i.e. "v4.0.0")
|
||||
- a branch (i.e. "master")
|
||||
- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977")
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with new-package-name =
|
||||
{ dependencies =
|
||||
[ "dependency1"
|
||||
, "dependency2"
|
||||
]
|
||||
, repo =
|
||||
"https://example.com/path/to/git/repo.git"
|
||||
, version =
|
||||
"<version>"
|
||||
}
|
||||
-------------------------------
|
||||
|
||||
Example:
|
||||
-------------------------------
|
||||
let upstream = --
|
||||
in upstream
|
||||
with benchotron =
|
||||
{ dependencies =
|
||||
[ "arrays"
|
||||
, "exists"
|
||||
, "profunctor"
|
||||
, "strings"
|
||||
, "quickcheck"
|
||||
, "lcg"
|
||||
, "transformers"
|
||||
, "foldable-traversable"
|
||||
, "exceptions"
|
||||
, "node-fs"
|
||||
, "node-buffer"
|
||||
, "node-readline"
|
||||
, "datetime"
|
||||
, "now"
|
||||
]
|
||||
, repo =
|
||||
"https://github.com/hdgarrood/purescript-benchotron.git"
|
||||
, version =
|
||||
"v7.0.0"
|
||||
}
|
||||
-------------------------------
|
||||
-}
|
||||
let upstream =
|
||||
https://github.com/purescript/package-sets/releases/download/psc-0.14.0-20210324/packages.dhall sha256:b4564d575da6aed1c042ca7936da97c8b7a29473b63f4515f09bb95fae8dddab
|
||||
|
||||
in upstream
|
19
purescript/free/spago.dhall
Normal file
19
purescript/free/spago.dhall
Normal file
|
@ -0,0 +1,19 @@
|
|||
{-
|
||||
Welcome to a Spago project!
|
||||
You can edit this file as you like.
|
||||
-}
|
||||
{ name = "my-project"
|
||||
, dependencies =
|
||||
[ "console"
|
||||
, "debug"
|
||||
, "effect"
|
||||
, "fixed-points"
|
||||
, "free"
|
||||
, "psci-support"
|
||||
, "tuples"
|
||||
, "undefined"
|
||||
, "variant"
|
||||
]
|
||||
, packages = ./packages.dhall
|
||||
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
|
||||
}
|
14
purescript/free/src/Exists.purs
Normal file
14
purescript/free/src/Exists.purs
Normal file
|
@ -0,0 +1,14 @@
|
|||
module Existsential where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
|
||||
foreign import data Test :: forall k. (k -> Type) -> Type
|
||||
foreign import data Exists :: forall a b. (a -> b) -> b
|
||||
|
||||
mkExists :: forall f a. f a -> Exists f
|
||||
mkExists = unsafeCoerce
|
||||
|
||||
runExists :: forall f r. (forall a. f a -> r) -> Exists f -> r
|
||||
runExists = unsafeCoerce
|
43
purescript/free/src/Lambda.purs
Normal file
43
purescript/free/src/Lambda.purs
Normal file
|
@ -0,0 +1,43 @@
|
|||
module Lambda where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Free (Free, liftF, resume)
|
||||
import Data.Either (Either(..))
|
||||
import Existsential (Exists, mkExists, runExists)
|
||||
|
||||
data CallData t f = CallData f (f -> t)
|
||||
data CallF a t = CallF (Exists (CallData t)) (t -> a)
|
||||
|
||||
data LambdaF a
|
||||
= Call (Exists (CallF a))
|
||||
|
||||
type Lambda = Free LambdaF
|
||||
|
||||
call :: forall a b. (a -> b) -> a -> Lambda b
|
||||
call f arg = liftF $ Call (mkExists (CallF callData identity))
|
||||
where
|
||||
callData = mkExists (CallData arg f)
|
||||
|
||||
eval :: forall a. Lambda a -> a
|
||||
eval = resume >>> case _ of
|
||||
Left (Call ex) -> eval $ run1 ex
|
||||
where
|
||||
run1 :: forall r. Exists (CallF r) -> r
|
||||
run1 = runExists (\(CallF ex' cb) -> cb $ run2 ex')
|
||||
|
||||
run2 :: forall t. Exists (CallData t) -> t
|
||||
run2 = runExists (\(CallData arg f) -> f arg)
|
||||
Right result -> result
|
||||
|
||||
test :: Lambda Int
|
||||
test = do
|
||||
result <- call ((+) 2) 3
|
||||
pure (result * 3)
|
||||
|
||||
instance functorLambdaF :: Functor LambdaF where
|
||||
map f (Call ex) = Call $ flip runExists ex (\(CallF ex' f') -> mkExists (CallF ex' $ f' >>> f))
|
||||
|
||||
-- instance showLambda :: Show a => Show (LambdaF a) where
|
||||
-- show (Call left right) = show left <> " " <> show right
|
||||
-- show (Lambda arg body) = "(\\" <> arg <> " -> " <> show body <> ")"
|
11
purescript/free/src/Main.purs
Normal file
11
purescript/free/src/Main.purs
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Main where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Effect (Effect)
|
||||
import Effect.Class.Console (logShow)
|
||||
import Lambda (eval, test)
|
||||
|
||||
main :: Effect Unit
|
||||
main = do
|
||||
logShow $ eval test
|
34
purescript/free/src/Math.purs
Normal file
34
purescript/free/src/Math.purs
Normal file
|
@ -0,0 +1,34 @@
|
|||
module Math where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Free (Free, liftF, resume)
|
||||
import Data.Either (Either(..))
|
||||
|
||||
data MathF a
|
||||
= Add Int Int (Int -> a)
|
||||
| Multiply Int Int (Int -> a)
|
||||
|
||||
type Math = Free MathF
|
||||
|
||||
---------- Helpers
|
||||
eval :: Math Int -> Int
|
||||
eval = resume >>> case _ of
|
||||
Right result -> result
|
||||
Left (Add l r cb) -> eval $ cb $ l + r
|
||||
Left (Multiply l r cb) -> eval $ cb $ l * r
|
||||
|
||||
seven :: Math Int
|
||||
seven = do
|
||||
four <- multiply_ 2 2
|
||||
add_ four 3
|
||||
|
||||
---------- Free boilerplate
|
||||
add_ :: Int -> Int -> Math Int
|
||||
add_ l r = liftF (Add l r identity)
|
||||
|
||||
multiply_ :: Int -> Int -> Math Int
|
||||
multiply_ l r = liftF (Multiply l r identity)
|
||||
|
||||
--------- Typeclass instances
|
||||
derive instance functorMath :: Functor MathF
|
11
purescript/free/test/Main.purs
Normal file
11
purescript/free/test/Main.purs
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Test.Main where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Effect (Effect)
|
||||
import Effect.Class.Console (log)
|
||||
|
||||
main :: Effect Unit
|
||||
main = do
|
||||
log "🍝"
|
||||
log "You should add some tests."
|
Loading…
Reference in a new issue