Skip to content
Merged
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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ what remains in each layer.
| Gate | Measured | Scope |
| --- | --- | --- |
| L0/L1 lexing, layout, parsing | 904/908 | non-FFI `layout`, `passing`, `failing`, `warning` files; the four differences are recorded DEC-16 intentional differences |
| L2 resolution | 72/72 failing, 270/413 passing | official `errorCode`s; 53 `passing` files stop on a missing module and 86 at P3 |
| L3 kinds | 35/48 failing | official kind `errorCode`s |
| L2 resolution | 72/72 failing, 276/413 passing | official `errorCode`s; 53 `passing` files stop on a missing module and 80 at P3 |
| L3 kinds | 36/48 failing | official kind `errorCode`s |
| L4 types | 35/50 failing | official `errorCode`s |
| L5 classes | 53/80 failing | official `errorCode`s |
| L6/M7 runtime | 124/413 passing | all 124 exit 0; 63 have no selected `main`; 53 stop on a missing module |
| L5 classes | 53/79 failing | official `errorCode`s |
| L6/M7 runtime | 125/413 passing | all 125 exit 0; 63 have no selected `main`; 53 stop on a missing module |
| M8 warnings, optimization | not measured | no scoreboard exists |

Run the scoreboards yourself:
Expand Down
63 changes: 63 additions & 0 deletions crates/psrs-driver/src/tests/functor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! The library's `Functor` class and its `<$>` operator.
//!
//! `Prelude` re-exports the class from `Data.Functor` and adds the `Effect`
//! instance. These tests check that one `map` covers arrays, `Maybe`,
//! `Either`, and `Effect`, and that mapping an effect does not run it.

use super::*;

#[test]
fn functor_map_transforms_array_maybe_and_either() {
let source = r#"
module Main where

import Prelude
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Effect.Console (log)

main :: Effect Unit
main = do
log (show ((\n -> n + 1) <$> [1, 2]))
log (case (\n -> n + 1) <$> Just 1 of
Just n -> show n
Nothing -> "nothing")
log (case (\n -> n + 1) <$> (Right 1 :: Either String Int) of
Right n -> show n
Left _ -> "left")
"#;
let Some(output) = run_with_wasmtime(source) else {
eprintln!("skipping: wasmtime is not installed");
return;
};
assert_eq!(output.status.code(), Some(0), "{output:?}");
assert_eq!(output.stdout, b"[2,3]\n2\n2\n", "{output:?}");
}

#[test]
fn mapping_an_effect_does_not_run_it_until_the_action_runs() {
let source = r#"
module Main where

import Prelude
import Effect.Console (log)

tick :: Effect Int
tick = do
log "tick"
pure 1

main :: Effect Unit
main = do
let pending = map (\n -> n + 1) tick
log "before"
value <- pending
log (show value)
"#;
let Some(output) = run_with_wasmtime(source) else {
eprintln!("skipping: wasmtime is not installed");
return;
};
assert_eq!(output.status.code(), Some(0), "{output:?}");
assert_eq!(output.stdout, b"before\ntick\n2\n", "{output:?}");
}
1 change: 1 addition & 0 deletions crates/psrs-driver/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod deriving;
mod effect_arity;
mod effects;
mod foldable;
mod functor;
mod guard_coverage;
mod operators;
mod partial_application;
Expand Down
2 changes: 2 additions & 0 deletions crates/psrs-driver/src/tests/module_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ fn loads_the_standard_library_from_disk_in_trusted_order() {
"Test.Assert",
"Data.Maybe",
"Data.Either",
"Data.Functor",
"Data.Tuple",
"Data.Foldable",
"WASI.Resource",
Expand Down Expand Up @@ -142,6 +143,7 @@ fn loads_the_standard_library_from_disk_in_trusted_order() {
|| path.ends_with("lib/Test/Assert.purs")
|| path.ends_with("lib/Data/Maybe.purs")
|| path.ends_with("lib/Data/Either.purs")
|| path.ends_with("lib/Data/Functor.purs")
|| path.ends_with("lib/Data/Tuple.purs")
|| path.ends_with("lib/Data/Foldable.purs")
|| path.ends_with("lib/WASI/Resource.purs")
Expand Down
45 changes: 33 additions & 12 deletions docs/design/D-04-suite-roadmap.md

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions docs/implementation/backend/effects.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
**Design:** [Effects](../../design/backend/fp/effects.md)

**Progress:** EF-01 through EF-13 are Verified on the explicit trusted-identity
contract. The 2026-10-04 runtime scoreboard is 124/413 (Wasmtime 49.0.2, `purs`
0.15.16). Those 124 files are the previous non-`Int` entries; each exits 0.
contract. The effect-entry measurement on 2026-10-04 was 124/413 (Wasmtime
49.0.2, `purs` 0.15.16). Those 124 files are the previous non-`Int` entries;
each exits 0. A later `Data.Functor` measurement on the same day moved the
board to 125/413; the added file is `passing/3549.purs`.
The 63 files with no selected `main` stay blocked. BE-21 stays Partial. A type
table changed after `lower_effects` returns is not checked again. Historical
records below describe the earlier encoding and are not the current evidence.
Expand Down
41 changes: 41 additions & 0 deletions stdlib/lib/Data/Functor.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
-- | The `Functor` class and the `<$>` operator.
-- |
-- | `map` is the class method. `Prelude` re-exports it and supplies the
-- | `Effect` instance, because this module cannot import `Prelude` without a
-- | cycle. The `Array` instance walks indexes with `arrayIndex` and builds the
-- | result with `arrayAppend`, the same primitives the rest of the library
-- | uses for arrays.
module Data.Functor
( class Functor
, map
, (<$>)
) where

import Data.Either (Either(..))
import Data.Maybe (Maybe(..))

-- | A type constructor that can apply a function to its contents.
class Functor f where
map :: forall a b. (a -> b) -> f a -> f b

infixl 4 map as <$>

instance functorArray :: Functor Array where
map f xs = mapFrom f xs 0

instance functorMaybe :: Functor Maybe where
map _ Nothing = Nothing
map f (Just value) = Just (f value)

instance functorEither :: Functor (Either a) where
map _ (Left value) = Left value
map f (Right value) = Right (f value)

-- | `mapFrom f xs i` is `f xs[i]` followed by the rest. The recursive call is
-- | an argument of `arrayAppend`, so this copies the tail at each index.
mapFrom :: forall a b. (a -> b) -> Array a -> Int -> Array b
mapFrom f xs index =
if intLt index (arrayLength xs) then
arrayAppend [f (arrayIndex xs index)] (mapFrom f xs (intAdd index 1))
else
[]
10 changes: 8 additions & 2 deletions stdlib/lib/Prelude.purs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ module Prelude
, pure
, bind
, discard
, class Functor
, map
, (<$>)
, apply
, runEffect
, trap
Expand Down Expand Up @@ -59,6 +61,7 @@ module Prelude
) where

import Data.Function (const, flip, (#), ($))
import Data.Functor (class Functor, map, (<$>))
import Data.Semigroup (class Semigroup, append, (<>))
import Data.Eq (class Eq, eq, notEq, (==), (/=))
import Data.Ord (class Ord, lessThan, lessThanOrEq, greaterThan, greaterThanOrEq, (<), (<=), (>), (>=))
Expand All @@ -74,8 +77,11 @@ foreign import "psrs:effect#bind" bind :: forall a b. Effect a -> (a -> Effect b
discard :: forall a b. Effect a -> (a -> Effect b) -> Effect b
discard first next = bind first next

map :: forall a b. (a -> b) -> Effect a -> Effect b
map f x = bind x (\v -> pure (f v))
-- | `map` on `Effect` is this instance, not a separate function. The body is
-- | the previous `Effect`-only `map`: it builds a new action and does not run
-- | `action` until that action is run.
instance functorEffect :: Functor Effect where
map f action = bind action (\value -> pure (f value))

apply :: forall a b. Effect (a -> b) -> Effect a -> Effect b
apply f x = bind f (\g -> bind x (\v -> pure (g v)))
Expand Down
1 change: 1 addition & 0 deletions stdlib/lib/trusted
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Effect.Console
Test.Assert
Data.Maybe
Data.Either
Data.Functor
Data.Tuple
Data.Foldable
WASI.Resource
Expand Down
Loading