count() > 0) { // Evaluate list contents $results = array_map(fn ($a) => ml_eval($a, $env), $expr->getData()); $fn = $results[0]; if ($fn instanceof Closure) { // If the first item is a function, call it $args = array_slice($results, 1); return $fn(...$args); } else { // Otherwise return new list with evaluated contents return new MLList($results); } } elseif ($expr instanceof MLHash) { // Hash: return new hash with all items evaluated $items = []; foreach ($expr->getData() as $key => $val) { $items[$key] = ml_eval($val, $env); } return new MLHash($items); } elseif ($expr instanceof MLSymbol) { return $env->get($expr->name()); } return $expr; } function ml_print($a): string { if ($a instanceof Closure) { return ''; } elseif ($a instanceof MLList) { return '(' . implode(' ', array_map('ml_print', $a->getData())) . ')'; } elseif ($a instanceof MLHash) { $items = []; foreach ($a->getData() as $key => $val) { $items[] = ml_print($key) . ':' . ml_print($val); } return '{' . implode(' ', $items) . '}'; } elseif ($a instanceof MLSymbol) { return $a->name(); } elseif ($a === true) { return 'true'; } elseif ($a === false) { return 'false'; } elseif ($a === null) { return 'null'; } elseif (is_string($a)) { return '"' . $a . '"'; } else { return $a; } } function ml_rep(string $input, MLEnv $env): string { $expressions = ml_read($input); $results = array_map(fn ($expr) => ml_eval($expr, $env), $expressions); return implode(" ", array_map('ml_print', $results)); }