mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 01:05:32 +01:00
Defining map and filter with lisp
This commit is contained in:
@ -36,6 +36,12 @@
|
||||
(>= b a)))
|
||||
|
||||
; Other functions in core.rs
|
||||
(def! int? (fn* [a]
|
||||
(= (type a) :int)))
|
||||
|
||||
(def! sym? (fn* [a]
|
||||
(= (type a) :symbol)))
|
||||
|
||||
(def! list? (fn* [a]
|
||||
(= (type a) :list)))
|
||||
|
||||
@ -109,13 +115,11 @@
|
||||
(def! help (fn* [symbol] "==SPECIAL FORM=="
|
||||
"symbol: Sym"
|
||||
"display an helper f or the specified symbol"
|
||||
"#alias: h"
|
||||
"#returns: NIL"))
|
||||
|
||||
(def! find (fn* [substring...] "==SPECIAL FORM=="
|
||||
"print all the known symbols partially matching <substring> in"
|
||||
"the current environment"
|
||||
"#alias f"
|
||||
"#returns: NIL"))
|
||||
|
||||
(def! quote (fn* [statement] "==SPECIAL FORM=="
|
||||
@ -137,3 +141,33 @@
|
||||
"; (help <symbol>) : print information about a symbol\n"
|
||||
";\n"
|
||||
"; enjoy ^.^\n"))
|
||||
|
||||
(def! reverse (fn* [x]
|
||||
"Reverses order of elements in the arg"
|
||||
(def! reverse-r (fn* [x t]
|
||||
(if (empty? x)
|
||||
t
|
||||
(reverse-r (cdr x) (cons (car x) t)))))
|
||||
(reverse-r x '())))
|
||||
|
||||
(def! map (fn* [f l]
|
||||
"Apply function f to all elements of l"
|
||||
(def! l (reverse l))
|
||||
(def! map-r (fn* [l p]
|
||||
(if (empty? l)
|
||||
p
|
||||
(map-r (cdr l) (cons (f (car l)) p)))))
|
||||
(map-r l '())))
|
||||
|
||||
(def! filter (fn* [f l]
|
||||
"Remove all elements that don't satisfy f"
|
||||
(def! l (reverse l))
|
||||
(def! filter-r (fn* [l p]
|
||||
(if (empty? l)
|
||||
p
|
||||
(do
|
||||
(def! t (car l))
|
||||
(if (f t)
|
||||
(filter-r (cdr l) (cons (car l) p))
|
||||
(filter-r (cdr l) p))))))
|
||||
(filter-r l '())))
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use std::{cell::RefCell, env, rc::Rc};
|
||||
|
||||
use crate::env::{
|
||||
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit,
|
||||
mal_map, Env,
|
||||
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_cons,
|
||||
mal_exit, Env,
|
||||
};
|
||||
|
||||
// This is the first time I implement a macro, and I'm copying it
|
||||
@ -81,7 +81,7 @@ pub fn ns_init() -> Env {
|
||||
"atom" => Fun(|a| Ok(Atom(Rc::new(RefCell::new(car(a).unwrap_or_default().clone())))), "Return an atom pointing to the given arg"),
|
||||
"deref" => Fun(|a| if_atom!(car(a)?), "Return the content of the atom argumet"),
|
||||
"reset!" => Fun(reset_bang, "Change the value of the Atom (frist argument) to the second argument"),
|
||||
"map" => Fun(mal_map, "Apply the first argument to all the elements of the second arguments"),
|
||||
"cons" => Fun(mal_cons, "Push to front if second element is a list"),
|
||||
"env" => Fun(|a| match env::var(car(a)?.if_string()?) {
|
||||
Ok(s) => Ok(Str(s.into())),
|
||||
_ => Ok(Nil),
|
||||
|
||||
40
src/env.rs
40
src/env.rs
@ -189,36 +189,18 @@ pub fn car_cdr(list: &[MalType]) -> Result<(&MalType, &[MalType]), MalErr> {
|
||||
Ok((car(list)?, cdr(list)))
|
||||
}
|
||||
|
||||
pub fn mal_map(args: &[MalType]) -> MalRet {
|
||||
let mut ret = Vec::new();
|
||||
let (lambda, list) = car_cdr(args)?;
|
||||
let list = car(list)?.if_list()?;
|
||||
match lambda {
|
||||
M::Fun(func, _) => {
|
||||
for el in list {
|
||||
ret.push(func(&[el.clone()])?);
|
||||
}
|
||||
// TODO: fix these chonky functions
|
||||
|
||||
pub fn mal_cons(args: &[MalType]) -> MalRet {
|
||||
match args.len() {
|
||||
2 => {
|
||||
let mut car = vec![args[0].clone()];
|
||||
let cdr = args[1].if_list()?;
|
||||
car.extend_from_slice(cdr);
|
||||
Ok(M::List(car.into()))
|
||||
}
|
||||
M::MalFun {
|
||||
params, ast, env, ..
|
||||
} => {
|
||||
for el in list {
|
||||
let inner_env = env_binds(env.clone(), params, &[el.clone()])?;
|
||||
match ast.as_ref() {
|
||||
M::List(ops) => {
|
||||
let mut last = MalType::Nil;
|
||||
for x in &ops[0..ops.len()] {
|
||||
last = eval(x, inner_env.clone())?;
|
||||
}
|
||||
ret.push(last)
|
||||
}
|
||||
_ => scream!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => scream!(),
|
||||
};
|
||||
Ok(MalType::List(ret.into()))
|
||||
_ => Err(MalErr::unrecoverable("cons: requires 2 arguments")),
|
||||
}
|
||||
}
|
||||
|
||||
fn first(list: &[MalType]) -> &[MalType] {
|
||||
|
||||
@ -21,7 +21,6 @@ forms!(NAME_DEF : "def!",
|
||||
NAME_FN : "fn*",
|
||||
NAME_FN_ALT : "λ",
|
||||
NAME_HELP : "help",
|
||||
NAME_HELP_ALT: "h",
|
||||
NAME_FIND : "find",
|
||||
NAME_QUOTE : "quote",
|
||||
NAME_OK : "ok?",
|
||||
@ -189,7 +188,7 @@ pub fn eval(ast: &MalType, env: Env) -> MalRet {
|
||||
NAME_FN | NAME_FN_ALT /* :) */ => {
|
||||
return fn_star_form(args, env.clone())
|
||||
}
|
||||
NAME_HELP | NAME_HELP_ALT => return help_form(args, env.clone()),
|
||||
NAME_HELP => return help_form(args, env.clone()),
|
||||
NAME_FIND => return find_form(args, env.clone()),
|
||||
// Oh God, what have I done
|
||||
NAME_QUOTE => return Ok(car(args)?.clone()),
|
||||
|
||||
@ -65,4 +65,9 @@ mod functional {
|
||||
fn map() {
|
||||
test!("map")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fil() {
|
||||
test!("fil")
|
||||
}
|
||||
}
|
||||
|
||||
4
tests/fil.mal
Normal file
4
tests/fil.mal
Normal file
@ -0,0 +1,4 @@
|
||||
; filter with builtin function
|
||||
(assert-eq (list '(1) '(2) '(3)) (filter car (list '(1) '() '(2) '() '(3))))
|
||||
; filter with lambda function
|
||||
(assert-eq (list 1 2 3) (filter int? (list 1 "string" 2 'symbol 3 :label)))
|
||||
Reference in New Issue
Block a user