Adding map for HOF

This commit is contained in:
teo3300
2024-06-17 02:16:51 +09:00
parent fb2aabbcef
commit 3b896fa6c4
5 changed files with 48 additions and 2 deletions

View File

@ -6,8 +6,10 @@ build-release:
test: test:
cargo test --release cargo test --release
install: build-release conf:
mkdir -p ${HOME}/.config/mal mkdir -p ${HOME}/.config/mal
cp -f core/core.mal ${HOME}/.config/mal/ cp -f core/core.mal ${HOME}/.config/mal/
install: build-release conf
sudo cp target/release/rust-mal /usr/local/bin/mal sudo cp target/release/rust-mal /usr/local/bin/mal
sudo chown ${USER} /usr/local/bin/mal sudo chown ${USER} /usr/local/bin/mal

View File

@ -1,7 +1,8 @@
use std::{cell::RefCell, env, rc::Rc}; use std::{cell::RefCell, env, rc::Rc};
use crate::env::{ use crate::env::{
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit, Env, any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit,
mal_map, Env,
}; };
// This is the first time I implement a macro, and I'm copying it // This is the first time I implement a macro, and I'm copying it
@ -80,6 +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"), "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"), "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"), "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"),
"env" => Fun(|a| match env::var(car(a)?.if_string()?) { "env" => Fun(|a| match env::var(car(a)?.if_string()?) {
Ok(s) => Ok(Str(s.into())), Ok(s) => Ok(Str(s.into())),
_ => Ok(Nil), _ => Ok(Nil),

View File

@ -189,6 +189,38 @@ pub fn car_cdr(list: &[MalType]) -> Result<(&MalType, &[MalType]), MalErr> {
Ok((car(list)?, cdr(list))) 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()])?);
}
}
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()))
}
fn first(list: &[MalType]) -> &[MalType] { fn first(list: &[MalType]) -> &[MalType] {
if list.len() > 1 { if list.len() > 1 {
&list[..list.len() - 1] &list[..list.len() - 1]

View File

@ -60,4 +60,9 @@ mod functional {
fn car_cdr() { fn car_cdr() {
test!("car-cdr") test!("car-cdr")
} }
#[test]
fn map() {
test!("map")
}
} }

5
tests/map.mal Normal file
View File

@ -0,0 +1,5 @@
; builtin map
(assert-eq '((1) (2) (3)) (map list '(1 2 3)))
; lambda map
(assert-eq '(2 3 4) (map (fn* [x] (+ x 1)) '(1 2 3)))