Skip to content

Commit

Permalink
Fix PR with latest master
Browse files Browse the repository at this point in the history
Make flake happy
  • Loading branch information
dbrattli committed Sep 24, 2020
1 parent c638a49 commit b34be63
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 26 deletions.
22 changes: 15 additions & 7 deletions oslash/do.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from collections import namedtuple

from .abc import Monad
from .typing import Monad
from .util import Unit

# This would be most natural to implement as a syntactic macro.
Expand All @@ -16,6 +16,7 @@

__all__ = ["do", "let", "guard"]


# TODO: guard belongs where in OSlash?
def guard(M, test):
"""Monadic guard.
Expand All @@ -28,8 +29,11 @@ def guard(M, test):
"""
return M.pure(Unit) if test else M()


# The kwargs syntax forces name to be a valid Python identifier.
MonadicLet = namedtuple("MonadicLet", "name value")


def let(**binding):
"""``<-`` for Python.
Expand All @@ -46,6 +50,7 @@ def let(**binding):
for k, v in binding.items():
return MonadicLet(k, v)


def do(*lines):
"""Do-notation.
Expand Down Expand Up @@ -122,14 +127,16 @@ def r(low, high):
"""
# The monadic bind and sequence operators, with any relevant whitespace.
bind = " | "
seq = " >> "
seq = " >> "

class env:
def __init__(self):
self.names = set()

def assign(self, k, v):
self.names.add(k)
setattr(self, k, v)

# simulate lexical closure property for env attrs
# - freevars: set of names that "fall in" from a surrounding lexical scope
def close_over(self, freevars):
Expand All @@ -140,6 +147,7 @@ def close_over(self, freevars):

# stuff used inside the eval
e = env()

def begin(*exprs): # args eagerly evaluated by Python
# begin(e1, e2, ..., en):
# perform side effects e1, e2, ..., e[n-1], return the value of en.
Expand All @@ -150,8 +158,8 @@ def begin(*exprs): # args eagerly evaluated by Python
bodys = []
begin_is_open = False
for j, item in enumerate(lines):
is_first = (j == 0)
is_last = (j == len(lines) - 1)
is_first = j == 0
is_last = j == len(lines) - 1

if isinstance(item, MonadicLet):
name, body = item
Expand Down Expand Up @@ -180,9 +188,9 @@ def begin(*exprs): # args eagerly evaluated by Python
# even though we use an imperative stateful object to implement it)
if not is_last:
if name:
code += "{bind:s}(lambda {n:s}:\nbegin(e.close_over({fvs}), e.assign('{n:s}', {n:s}), ".format(bind=bind,
n=name,
fvs=freevars)
code += "{bind:s}(lambda {n:s}:\nbegin(e.close_over({fvs}), e.assign('{n:s}', {n:s}), ".format(
bind=bind, n=name, fvs=freevars
)
begin_is_open = True
else:
if is_first:
Expand Down
18 changes: 18 additions & 0 deletions oslash/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,24 @@ def __iter__(self) -> Iterator:
yield xs.head()
xs = xs.tail()

def __or__(self, func):
"""Use | as operator for bind.
Provide the | operator instead of the Haskell >>= operator
"""
return self.bind(func)

def __rshift__(self, next):
"""The "Then" operator.
Sequentially compose two monadic actions, discarding any value
produced by the first, like sequencing operators (such as the
semicolon) in imperative languages.
Haskell: (>>) :: m a -> m b -> m b
"""
return self.bind(lambda _: next)

def __add__(self, other):
return self.append(other)

Expand Down
20 changes: 1 addition & 19 deletions oslash/typing/monad.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
TSource = TypeVar('TSource')
TResult = TypeVar('TResult')


@runtime_checkable
class Monad(Protocol[TSource]):
"""Monad protocol"""
Expand Down Expand Up @@ -80,22 +81,3 @@ def unit(value: TSource) -> 'Monad[TSource]':
# bound argument into the outer level."""

# return self.bind(identity)

class MonadEx:
def __or__(self, func):
"""Use | as operator for bind.
Provide the | operator instead of the Haskell >>= operator
"""
return self.bind(func)

def __rshift__(self, next):
"""The "Then" operator.
Sequentially compose two monadic actions, discarding any value
produced by the first, like sequencing operators (such as the
semicolon) in imperative languages.
Haskell: (>>) :: m a -> m b -> m b
"""
return self.bind(lambda _: next)

0 comments on commit b34be63

Please sign in to comment.