Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option existential quantifiers #124

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Next version

### API changes

- Add `Option.isNoneOr` and `Option.isSomeAnd` /~https://github.com/rescript-association/rescript-core/pull/124

## 0.4.0

### API changes
Expand Down
18 changes: 18 additions & 0 deletions src/Core__Option.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ function compare(a, b, cmp) {
}
}

function isSomeAnd(o, p) {
if (o !== undefined) {
return Curry._1(p, Caml_option.valFromOption(o));
} else {
return false;
}
}

function isNoneOr(o, p) {
if (o !== undefined) {
return Curry._1(p, Caml_option.valFromOption(o));
} else {
return true;
}
}

export {
filter ,
forEach ,
Expand All @@ -117,5 +133,7 @@ export {
isNone ,
equal ,
compare ,
isSomeAnd ,
isNoneOr ,
}
/* No side effect */
12 changes: 12 additions & 0 deletions src/Core__Option.res
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,15 @@ let compare = (a, b, cmp) =>
| (Some(_), None) => Core__Ordering.greater
| (None, None) => Core__Ordering.equal
}

let isSomeAnd = (o, p) =>
switch o {
| None => false
| Some(v) => p(v)
}

let isNoneOr = (o, p) =>
switch o {
| None => true
| Some(v) => p(v)
}
30 changes: 30 additions & 0 deletions src/Core__Option.resi
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,33 @@ compare(None, None, clockCompare) // 0.
```
*/
let compare: (option<'a>, option<'b>, ('a, 'b) => Core__Ordering.t) => Core__Ordering.t

/**
`isSomeAnd(option, predicate)` tests whether the option is `Some` **and** the predicate applied to its value is true.

An option can be thought of as an array with 0 or 1 items in it. `isSomeAnd` is similar to `Array.some` and acts like the "there exists" quantifier in mathematics. It returns false for a `None` option.

## Examples

```rescript
Option.isSomeAnd(None, i => i >= 0) // false
Option.isSomeAnd(Some(3), i => i > 1) // true
Option.isSomeAnd(Some(3), i => i < 0) // false
```
*/
let isSomeAnd: (option<'a>, 'a => bool) => bool

/**
`isNoneOr(option, predicate)` tests whether the option is `None` **or** the predicate applied to its value is true.

An option can be thought of as an array with 0 or 1 items in it. `isNoneOr` is similar to `Array.every` and acts like the "for all" quantifier in mathematics. In particular it returns true when the option is `None`.

## Examples

```rescript
Option.isNoneOr(None, i => i >= 0) // true
Option.isNoneOr(Some(3), i => i > 1) // true
Option.isNoneOr(Some(3), i => i < 0) // false
```
*/
let isNoneOr: (option<'a>, 'a => bool) => bool
77 changes: 77 additions & 0 deletions test/OptionTests.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as Test from "./Test.mjs";
import * as Caml_obj from "rescript/lib/es6/caml_obj.js";
import * as Core__Option from "../src/Core__Option.mjs";

var eq = Caml_obj.equal;

function isPositive(i) {
return i > 0;
}

Test.run([
[
"OptionTests.res",
12,
13,
47
],
"isSomeAnd: if None, return false"
], Core__Option.isSomeAnd(undefined, isPositive), eq, false);

Test.run([
[
"OptionTests.res",
19,
13,
55
],
"isSomeAnd: if Some and true, return true"
], Core__Option.isSomeAnd(1, isPositive), eq, true);

Test.run([
[
"OptionTests.res",
25,
13,
57
],
"isSomeAnd: if Some and false, return false"
], Core__Option.isSomeAnd(-1, isPositive), eq, false);

Test.run([
[
"OptionTests.res",
31,
20,
52
],
"isNoneOr: if None, return true"
], Core__Option.isNoneOr(undefined, isPositive), eq, true);

Test.run([
[
"OptionTests.res",
33,
13,
54
],
"isNoneOr: if Some and true, return true"
], Core__Option.isNoneOr(1, isPositive), eq, true);

Test.run([
[
"OptionTests.res",
39,
13,
56
],
"isNoneOr: if Some and false, return false"
], Core__Option.isNoneOr(-1, isPositive), eq, false);

export {
eq ,
isPositive ,
}
/* Not a pure module */
43 changes: 43 additions & 0 deletions test/OptionTests.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
open RescriptCore

let eq = (a, b) => a == b

// ======================
// isSomeAnd and isNoneOr
// ======================

let isPositive = i => i > 0

Test.run(
__POS_OF__("isSomeAnd: if None, return false"),
None->Option.isSomeAnd(isPositive),
eq,
false,
)

Test.run(
__POS_OF__("isSomeAnd: if Some and true, return true"),
Some(1)->Option.isSomeAnd(isPositive),
eq,
true,
)
Test.run(
__POS_OF__("isSomeAnd: if Some and false, return false"),
Some(-1)->Option.isSomeAnd(isPositive),
eq,
false,
)

Test.run(__POS_OF__("isNoneOr: if None, return true"), None->Option.isNoneOr(isPositive), eq, true)
Test.run(
__POS_OF__("isNoneOr: if Some and true, return true"),
Some(1)->Option.isNoneOr(isPositive),
eq,
true,
)
Test.run(
__POS_OF__("isNoneOr: if Some and false, return false"),
Some(-1)->Option.isNoneOr(isPositive),
eq,
false,
)
10 changes: 7 additions & 3 deletions test/TestSuite.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as IntTests from "./IntTests.mjs";
import * as TestTests from "./TestTests.mjs";
import * as ArrayTests from "./ArrayTests.mjs";
import * as ErrorTests from "./ErrorTests.mjs";
import * as OptionTests from "./OptionTests.mjs";
import * as PromiseTest from "./PromiseTest.mjs";
import * as ResultTests from "./ResultTests.mjs";
import * as TypedArrayTests from "./TypedArrayTests.mjs";
Expand Down Expand Up @@ -34,8 +35,6 @@ var forEachIfOkCallFunction = ResultTests.forEachIfOkCallFunction;

var forEachIfErrorDoNotCallFunction = ResultTests.forEachIfErrorDoNotCallFunction;

var eq = TypedArrayTests.eq;

var num1 = TypedArrayTests.num1;

var num2 = TypedArrayTests.num2;
Expand All @@ -50,6 +49,10 @@ var areSame = TypedArrayTests.areSame;

var o = TypedArrayTests.o;

var eq = OptionTests.eq;

var isPositive = OptionTests.isPositive;

export {
bign ,
TestError ,
Expand All @@ -64,13 +67,14 @@ export {
$$catch ,
forEachIfOkCallFunction ,
forEachIfErrorDoNotCallFunction ,
eq ,
num1 ,
num2 ,
num3 ,
assertTrue ,
assertWillThrow ,
areSame ,
o ,
eq ,
isPositive ,
}
/* IntTests Not a pure module */
1 change: 1 addition & 0 deletions test/TestSuite.res
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ include ArrayTests
include IntTests
include ResultTests
include TypedArrayTests
include OptionTests