README.md | enso.nim: attempt added for safer Exception handling, README updated to reflect current state and philosophy
This commit is contained in:
@ -9,7 +9,11 @@ As a result, Enso is not exactly fantastical and may not be for you, unless you
|
||||
|
||||
# Usage
|
||||
|
||||
Enso provides the IO Thunk in order to handle data and functions. Functions and any data made pure via `to_IO` are lazily evaluated and then able to be used on the spot or when necessary, with the `run` function intended to sugar the usage of functions stored this way. `flatmap`, `map`, `join`, and `lift` are also provided in order to be used with the IO Thunk or with any other potentially impure functions to be executed in the Monad's context. It's mostly bare bones other than that besides `readstr` to read from a UNIX file descriptor and `strput` to write a string to STDOUT.
|
||||
Enso provides the IO Thunk in order to handle data and functions. Functions and any data made pure via `to_IO` are lazily evaluated and then able to be used on the spot or when necessary, with the `run` function intended to sugar the usage of functions stored this way. `flatmap`, `map`, `join`, and `lift` are also provided in order to be used with the IO Thunk or with any other potentially impure functions to be executed in the Monad's context. It's mostly bare bones other than that besides `readln` to read from a file descriptor and `strput` to write a string to STDOUT.
|
||||
|
||||
As well, Enso provides `attempt` to help work with effectful procedures in Nim that have the capability to raise an Exception, `attempt` moves an IO Thunk with the capability to raise an Exception to be detonated within an unsafe procedure where the effect will happen, and passing off a Some or None to then be evaluated for handling any potential errors in a safer, much more graceful manner. `attempt` pairs fantastically with `lift` for removing any potential issues caused by effectful code.
|
||||
|
||||
It is important still as the programmer to understand that while many of Enso's provided utilities can allow you to perform nicer Functional Programming in Nim, it does not hold your hand the way a language like Haskell or OCaml will with the paradigm, and you have to hold yourself accountable to the paradigm. That is to say, how you use Enso will reflect who you are as a programmer and who you are when the compiler stops holding your hand. Enso also will teach the academics how to be engineers and the engineers how to be academics.
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
36
src/enso.nim
36
src/enso.nim
@ -3,11 +3,13 @@ import std/[options, os, sugar]
|
||||
# Declarations
|
||||
|
||||
type
|
||||
Error* = enum OK, ERR
|
||||
IO*[T] = proc(): T
|
||||
Unit* = object
|
||||
|
||||
func attempt*[T](uf: IO[T]): Option[T]
|
||||
func attempt*(uf: IO[void]): Option[Unit]
|
||||
func fileread*(file: string): IO[Option[string]]
|
||||
func filewrite*(data: string, file: string): IO[Error]
|
||||
func filewrite*(data: string, file: string): IO[Option[Unit]]
|
||||
func flatmap*[T, U](io: IO[T], fn: T -> IO[U]): IO[U]
|
||||
func lift*(fn: proc(): void): IO[void]
|
||||
func lift*[T](fn: proc(): T): IO[T]
|
||||
@ -20,31 +22,35 @@ func to_IO*[T](val: T): IO[T]
|
||||
|
||||
# Unsafe
|
||||
|
||||
proc read_unsafe(file: string): Option[string] =
|
||||
proc unsafe[T](uf: IO[T]): Option[T] =
|
||||
try:
|
||||
let data: string = readFile(file)
|
||||
some(data)
|
||||
except IOError:
|
||||
none(string)
|
||||
let sf: T = uf()
|
||||
some(sf)
|
||||
except:
|
||||
none(T)
|
||||
|
||||
proc write_unsafe(data: string, file: string): Error =
|
||||
proc unsafe(uf: IO[void]): Option[Unit] =
|
||||
try:
|
||||
writeFile(file, data)
|
||||
OK
|
||||
except IOError:
|
||||
ERR
|
||||
run uf
|
||||
some(Unit())
|
||||
except:
|
||||
none(Unit)
|
||||
|
||||
# Definitions
|
||||
|
||||
func attempt*[T](uf: IO[T]): Option[T] = unsafe(uf)
|
||||
|
||||
func attempt*(uf: IO[void]): Option[Unit] = unsafe(uf)
|
||||
|
||||
func fileread*(file: string): IO[Option[string]] =
|
||||
proc(): Option[string] =
|
||||
if fileExists(file):
|
||||
read_unsafe(file)
|
||||
attempt(lift () => readFile(file))
|
||||
else:
|
||||
none(string)
|
||||
|
||||
func filewrite*(data: string, file: string): IO[Error] =
|
||||
proc(): Error = write_unsafe(data, file)
|
||||
func filewrite*(data: string, file: string): IO[Option[Unit]] =
|
||||
proc(): Option[Unit] = attempt(lift () => writeFile(file, data))
|
||||
|
||||
func flatmap*[T, U](io: IO[T], fn: T -> IO[U]): IO[U] = join(map(io, fn))
|
||||
|
||||
|
||||
@ -43,8 +43,8 @@ func main() =
|
||||
else:
|
||||
run strput("flat had no data")
|
||||
|
||||
let writer: Error = run filewrite("Hello world!\n", "test.txt")
|
||||
if writer == OK:
|
||||
let writer: IO[Option[Unit]] = filewrite("Hello world!\n", "test.txt")
|
||||
if writer().isSome:
|
||||
run strput("Successfully wrote test.txt!")
|
||||
else:
|
||||
run strput("Could not write test.txt!")
|
||||
|
||||
Reference in New Issue
Block a user