Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hymn

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hymn

Hy Monad Notation - a monad library for Hy

  • 1.1.0
  • PyPI
  • Socket score

Maintainers
1

========================================== Hy Monad Notation - a monad library for Hy

Introduction

Hymn is a monad library for Hy/Python, with do notation for monad comprehension.

Code are better than words.

The continuation monad

.. code-block:: clojure

=> (import hymn.dsl [cont-m call/cc]) => ;; computations in continuation passing style => (defn double [x] (cont-m.unit (* x 2))) => (setv length (cont-m.monadic len)) => ;; chain with bind => (.run (>> (cont-m.unit [1 2 3]) length double)) 6 => (defn square [n] (call/cc (fn [k] (k (** n 2))))) => (.run (square 12)) 144 => (.run (square 12) (fn [x] (+ x 1))) 145 => (.run (square 12) str) "144" => (require hymn.dsl [do-monad-return]) => (.run (do-monad-return [sqr (square 42)] (.format "answer^2 = {}" sqr))) "answer^2 = 1764"

The either monad

.. code-block:: clojure

=> (import hymn.dsl [Left Right either failsafe]) => (require hymn.dsl [do-monad-return]) => ;; do notation with either monad => (do-monad-return [a (Right 1) b (Right 2)] (/ a b)) Right(0.5) => (do-monad-return [a (Right 1) b (Left NaN)] (/ a b)) Left(nan) => ;; failsafe is a function decorator that wraps return value into either => (import hy.pyops [/]) => (setv safe-div (failsafe /)) => ;; returns Right if nothing wrong => (safe-div 4 2) Right(2.0) => ;; returns Left when bad thing happened, like exception being thrown => (safe-div 1 0) Left(ZeroDivisionError('division by zero')) => ;; function either tests the value and calls functions accordingly => (either print (fn [x] (+ x 1)) (safe-div 4 2)) 3.0 => (either print (fn [x] (+ x 1)) (safe-div 1 0)) division by zero

The identity monad

.. code-block:: clojure

=> (import hymn.dsl [identity-m]) => (require hymn.dsl [do-monad-return]) => ;; do notation with identity monad is like let binding => (do-monad-return [a (identity-m 1) b (identity-m 2)] (+ a b)) Identity(3)

The lazy monad

.. code-block:: clojure

=> (import hymn.dsl [force]) => (require hymn.dsl [lazy]) => ;; lazy computation implemented as monad => ;; macro lazy creates deferred computation => (setv a (lazy (print "evaluate a") 42)) => ;; the computation is deferred, notice the value is shown as '' => a Lazy() => ;; evaluate it => (.evaluate a) evaluate a 42 => ;; now the value is cached => a Lazy(42) => ;; calling evaluate again will not trigger the computation => (.evaluate a) 42 => (setv b (lazy (print "evaluate b") 21)) => b Lazy() => ;; force evaluate the computation, same as calling .evaluate on the monad => (force b) evaluate b 21 => ;; force on values other than lazy return the value unchanged => (force 42) 42 => (require hymn.dsl [do-monad-return]) => ;; do notation with lazy monad => (setv c (do-monad-return ... [x (lazy (print "get x") 1) ... y (lazy (print "get y") 2)] ... (+ x y))) => ;; the computation is deferred => c Lazy() => ;; do it! => (force c) get x get y 3 => ;; again => (force c) 3

The list monad

.. code-block:: clojure

=> (import hymn.dsl [list-m]) => (require hymn.dsl [do-monad-return]) => ;; use list-m contructor to turn sequence into list monad => (setv xs (list-m (range 2))) => (setv ys (list-m (range 3))) => ;; do notation with list monad is list comprehension => (list (do-monad-return [x xs y ys :when (not (= 0 y))] (/ x y))) [0.0 0.0 1.0 0.5] => (require hymn.dsl :readers [@]) => ;; @ is the reader macro for list-m => (list ... (do-monad-return ... [x #@ (range 2) ... y #@ (range 3) ... :when (not (= 0 y))] ... (/ x y))) [0.0 0.0 1.0 0.5]

The maybe monad

.. code-block:: clojure

=> (import hymn.dsl [Just Nothing maybe]) => (require hymn.dsl [do-monad-return]) => ;; do notation with maybe monad => (do-monad-return [a (Just 1) b (Just 1)] (/ a b)) Just(1.0) => ;; Nothing yields Nothing => (do-monad-return [a Nothing b (Just 1)] (/ a b)) Nothing => ;; maybe is a function decorator that wraps return value into maybe => ;; a safe-div with maybe monad => (import hy.pyops [/]) => (setv safe-div (maybe /)) => (safe-div 42 42) Just(1.0) => (safe-div 42 'answer) Nothing => (safe-div 42 0) Nothing

The reader monad

.. code-block:: clojure

=> (import hymn.dsl [lookup-reader]) => (require hymn.dsl [do-monad-return]) => ;; do notation with reader monad, => ;; lookup assumes the environment is subscriptable => (setv r (do-monad-return [a (lookup-reader 'a) b (lookup-reader 'b)] (+ a b))) => ;; run reader monad r with environment => (.run r {'a 1 'b 2}) 3

The state monad

.. code-block::

=> (import hymn.dsl [lookup-state set-value]) => (require hymn.dsl [do-monad-return]) => ;; do notation with state monad, => ;; set-value sets the value with key in the state => (setv s (do-monad-return [x (lookup-state "a") _ (set-value "b" (+ x 1))] x)) => ;; run state monad s with initial state => (.run s {"a" 1}) #(1 {"a" 1 "b" 2})

The writer monad

.. code-block:: clojure

=> (import hymn.dsl [tell]) => (require hymn.dsl [do-monad-return]) => ;; do notation with writer monad => (do-monad-return [_ (tell "hello") _ (tell " world")] None) StrWriter((None, 'hello world')) => ;; int is monoid, too => (.execute (do-monad-return [_ (tell 1) _ (tell 2) _ (tell 3)] None)) 6

Operations on monads

.. code-block:: clojure

=> (import hymn.dsl [lift]) => ;; lift promotes function into monad => (import hy.pyops [+]) => (setv m+ (lift +)) => ;; lifted function can work on any monad => ;; on the maybe monad => (import hymn.dsl [Just Nothing]) => (m+ (Just 1) (Just 2)) Just(3) => (m+ (Just 1) Nothing) Nothing => ;; on the either monad => (import hymn.dsl [Left Right]) => (m+ (Right 1) (Right 2)) Right(3) => (m+ (Left 1) (Right 2)) Left(1) => ;; on the list monad => (import hymn.dsl [list-m]) => (list (m+ (list-m "ab") (list-m "123"))) ["a1" "a2" "a3" "b1" "b2" "b3"] => (list (m+ (list-m "+-") (list-m "123") (list-m "xy"))) ["+1x" "+1y" "+2x" "+2y" "+3x" "+3y" "-1x" "-1y" "-2x" "-2y" "-3x" "-3y"] => ;; can be used as normal function => (import functools [reduce]) => (reduce m+ [(Just 1) (Just 2) (Just 3)]) Just(6) => (reduce m+ [(Just 1) Nothing (Just 3)]) Nothing => ;; <-r is an alias of lookup-reader => (import hymn.dsl [<-r]) => (require hymn.dsl :readers [^]) => ;; ^ is the reader macro for lift => (setv p (#^ print (<-r 'message) :end (<-r 'end))) => (.run p {'message "Hello world" 'end "!\n"}) Hello world! => ;; pseudo random number - linear congruential generator => (import hymn.dsl [state-m get-state set-state]) => (setv random ... (>> get-state ... (fn [s] (state-m.unit (% (+ (* s 69069) 1) (** 2 32)))) ... set-state)) => (.run random 1234) #(1234 85231147) => ;; random can be even shorter by using modify => (import hymn.dsl [modify]) => (setv random (modify (fn [s] (% (+ (* s 69069) 1) (** 2 32))))) => (.run random 1234) #(1234 85231147) => ;; use replicate to do computation repeatly => (import hymn.dsl [replicate]) => (.evaluate (replicate 5 random) 42) [42 2900899 2793697416 2186085609 1171637142] => ;; sequence on writer monad => (import hymn.dsl [sequence]) => (import hymn.dsl [tell]) => (.execute (sequence (map tell (range 1 101)))) 5050

Using Hymn in Python

.. code-block:: python

from hymn.dsl import * sequence(map(tell, range(1, 101))).execute() 5050 msum = lift(sum) msum(sequence(map(maybe(int), "12345"))) Just(15) msum(sequence(map(maybe(int), "12345a"))) Nothing @failsafe ... def safe_div(a, b): ... return a / b ... safe_div(1.0, 2) Right(0.5) safe_div(1, 0) Left(ZeroDivisionError(...))

Requirements

  • hy >= 0.27.0

For hy version 0.19, please install hymn 0.9

For hy version 0.14, please install hymn 0.8

For hy version 0.13, please install hymn 0.7.

For hy version 0.12, please install hymn 0.6.

For hy version 0.11 and earlier, please install hymn 0.5.

See Changelog section in documentation for details.

Installation

Install from PyPI::

pip install hymn

License

BSD New, see LICENSE for details.

Documentation: https://hymn.readthedocs.io/

Issue Tracker: https://github.com/pyx/hymn/issues/

Source Package @ PyPI: https://pypi.python.org/pypi/hymn/

Git Repository @ Github: https://github.com/pyx/hymn/

Git Repository @ Gitlab: https://gitlab.com/pyx/hymn/

Keywords

FAQs


Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc