Implement reification from Maps.

This commit is contained in:
KtorZ
2024-03-01 16:14:23 +01:00
parent 5272f5ecee
commit bfcfc5c41b
9 changed files with 257 additions and 184 deletions

View File

@@ -1,7 +1,16 @@
# This file was generated by Aiken
# You typically do not need to edit this file
[[requirements]]
name = "aiken-lang/stdlib"
version = "main"
source = "github"
[[packages]]
name = "aiken-lang/stdlib"
version = "main"
requirements = []
packages = []
source = "github"
[etags]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1709304545, nanos_since_epoch = 842241000 }, "cf946239d3dd481ed41f20e56bf24910b5229ea35aa171a708edc2a47fc20a7b"]

View File

@@ -1,3 +1,8 @@
name = "aiken-lang/acceptance_test_095"
version = "0.0.0"
description = ""
[[dependencies]]
name = "aiken-lang/stdlib"
version = "main"
source = "github"

View File

@@ -0,0 +1,130 @@
use aiken/builtin
const max_int: Int = 255
pub type PRNG {
Seeded { seed: Int, choices: List<Int> }
Replayed { choices: List<Int> }
}
pub type Fuzzer<a> =
fn(PRNG) -> Option<(PRNG, a)>
// Primitives
pub fn any_int() -> Fuzzer<Int> {
fn(prng: PRNG) -> Option<(PRNG, Int)> {
when prng is {
Seeded { seed, choices } -> {
let digest =
seed
|> builtin.integer_to_bytearray(True, 32, _)
|> builtin.blake2b_256()
let choice =
digest
|> builtin.index_bytearray(0)
let new_seed =
digest
|> builtin.slice_bytearray(1, 4, _)
|> builtin.bytearray_to_integer(True, _)
Some((Seeded { seed: new_seed, choices: [choice, ..choices] }, choice))
}
Replayed { choices } ->
when choices is {
[] -> None
[head, ..tail] ->
if head >= 0 && head <= max_int {
Some((Replayed { choices: tail }, head))
} else {
None
}
}
}
}
}
pub fn constant(a: a) -> Fuzzer<a> {
fn(s0) { Some((s0, a)) }
}
pub fn and_then(fuzz_a: Fuzzer<a>, f: fn(a) -> Fuzzer<b>) -> Fuzzer<b> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) -> f(a)(s1)
None -> None
}
}
}
pub fn map(fuzz_a: Fuzzer<a>, f: fn(a) -> b) -> Fuzzer<b> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) -> Some((s1, f(a)))
None -> None
}
}
}
pub fn map2(fuzz_a: Fuzzer<a>, fuzz_b: Fuzzer<b>, f: fn(a, b) -> c) -> Fuzzer<c> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) ->
when fuzz_b(s1) is {
Some((s2, b)) -> Some((s2, f(a, b)))
None -> None
}
None -> None
}
}
}
pub fn map4(
fuzz_a: Fuzzer<a>,
fuzz_b: Fuzzer<b>,
fuzz_c: Fuzzer<c>,
fuzz_d: Fuzzer<d>,
f: fn(a, b, c, d) -> result,
) -> Fuzzer<result> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) ->
when fuzz_b(s1) is {
Some((s2, b)) ->
when fuzz_c(s2) is {
Some((s3, c)) ->
when fuzz_d(s3) is {
Some((s4, d)) -> Some((s4, f(a, b, c, d)))
None -> None
}
None -> None
}
None -> None
}
None -> None
}
}
}
// Builders
fn any_bool() -> Fuzzer<Bool> {
any_int() |> map(fn(n) { n <= 127 })
}
fn any_list(fuzz_a: Fuzzer<a>) -> Fuzzer<List<a>> {
any_bool()
|> and_then(
fn(continue) {
if continue {
map2(fuzz_a, any_list(fuzz_a), fn(head, tail) { [head, ..tail] })
} else {
constant([])
}
},
)
}

View File

@@ -1,166 +1,47 @@
use aiken/builtin
const max_int: Int = 255
pub type PRNG {
Seeded { seed: Int, choices: List<Int> }
Replayed { choices: List<Int> }
}
type Fuzzer<a> =
fn(PRNG) -> Option<(PRNG, a)>
// Primitives
fn any_int(prng: PRNG) -> Option<(PRNG, Int)> {
when prng is {
Seeded { seed, choices } -> {
let digest =
seed
|> builtin.integer_to_bytearray(True, 32, _)
|> builtin.blake2b_256()
let choice =
digest
|> builtin.index_bytearray(0)
let new_seed =
digest
|> builtin.slice_bytearray(1, 4, _)
|> builtin.bytearray_to_integer(True, _)
Some((Seeded { seed: new_seed, choices: [choice, ..choices] }, choice))
}
Replayed { choices } ->
when choices is {
[] -> None
[head, ..tail] ->
if head >= 0 && head <= max_int {
Some((Replayed { choices: tail }, head))
} else {
None
}
}
}
}
pub fn constant(a: a) -> Fuzzer<a> {
fn(s0) { Some((s0, a)) }
}
pub fn and_then(fuzz_a: Fuzzer<a>, f: fn(a) -> Fuzzer<b>) -> Fuzzer<b> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) -> f(a)(s1)
None -> None
}
}
}
pub fn map(fuzz_a: Fuzzer<a>, f: fn(a) -> b) -> Fuzzer<b> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) -> Some((s1, f(a)))
None -> None
}
}
}
pub fn map2(fuzz_a: Fuzzer<a>, fuzz_b: Fuzzer<b>, f: fn(a, b) -> c) -> Fuzzer<c> {
fn(s0) {
when fuzz_a(s0) is {
Some((s1, a)) ->
when fuzz_b(s1) is {
Some((s2, b)) -> Some((s2, f(a, b)))
None -> None
}
None -> None
}
}
}
// Builders
fn any_bool() -> Fuzzer<Bool> {
any_int |> map(fn(n) { n <= 127 })
}
fn any_list(fuzz_a: Fuzzer<a>) -> Fuzzer<List<a>> {
any_bool()
|> and_then(
fn(continue) {
if continue {
map2(fuzz_a, any_list(fuzz_a), fn(head, tail) { [head, ..tail] })
} else {
constant([])
}
},
)
}
fn any_season() -> Fuzzer<Season> {
any_int
|> and_then(
fn(i) {
let n = i % 3
if n == 0 {
any_bool() |> map(Winter)
} else if n == 1 {
constant(Spring(i))
} else if n == 2 {
constant(Summer)
} else {
constant(Fall)
}
},
)
}
fn length(xs: List<a>) -> Int {
when xs is {
[] -> 0
[_, ..tail] -> 1 + length(tail)
}
}
fn filter(xs: List<a>, f: fn(a) -> Bool) -> List<a> {
when xs is {
[] ->
[]
[head, ..tail] ->
if f(head) {
[head, ..filter(tail, f)]
} else {
filter(tail, f)
}
}
}
// Properties
use aiken/dict.{Dict}
use aiken/fuzz.{Fuzzer}
use aiken/int
pub type Season {
Winter(Bool)
Spring(Int)
Winter
Spring
Summer
Fall
}
// test prop_is_never_summer(xs via any_list(any_season())) {
// filter(xs, fn(x) { x == Summer }) == []
// }
fn compare_season(a: Season, b: Season) -> Ordering {
let season_to_int =
fn(season) {
when season is {
Winter -> 0
Spring -> 1
Summer -> 2
Fall -> 3
}
}
test prop_is_always_cold_in_winter(xs via any_list(any_season())) {
is_always_cold_in_winter(xs)
int.compare(season_to_int(a), season_to_int(b))
}
test prop_is_always_cold_in_winter_2() {
is_always_cold_in_winter([Winter(True)])
fn any_year() -> Fuzzer<Dict<Season, Int>> {
fuzz.map4(
fuzz.any_int(),
fuzz.any_int(),
fuzz.any_int(),
fuzz.any_int(),
fn(a, b, c, d) {
dict.new()
|> dict.insert(Winter, a, compare_season)
|> dict.insert(Spring, b, compare_season)
|> dict.insert(Summer, c, compare_season)
|> dict.insert(Fall, d, compare_season)
},
)
}
fn is_always_cold_in_winter(xs: List<Season>) -> Bool {
when xs is {
[Winter(cold), ..tail] -> cold && is_always_cold_in_winter(tail)
_ -> True
test prop_always_cold_in_winter(year via any_year()) {
when dict.get(year, Winter) is {
Some(temperature) -> temperature <= 10
_ -> fail @"failed to get?"
}
}