[comp.emacs] apply, mapcar, lack of setenv

csuwn@cu.warwick.ac.uk (Max) (06/02/89)

I have just started working with emacs-lisp having some exprience with
Franz Lisp. Without the manuals finding out about functions and
variables is a long boring process of searching the respective entire
completions, or other standard libries.

So far all has gone well, I found out how to create processes, and set
sentinels to watch over them. However in some cases some things seem
not to work as expected - or infact are not included in emacs.

1: Apply, and mapcar

I frequently want to do the following;

(apply 'or (mapcar 'function list)) where function returns t or nil.

Problem: Apply dosent know about the function or.
Solution:

(cond ((<= 1 (apply '+ (mapcar 'nfunction list))) t)
      (t nil))

Where nfunction returns 1 or 0 instead of t or nil respectively.

Is there a more elegant solution, or am I perhaps missing something.
Also why no lambda function in emacs (is it that hard to implement),
as its use with mapcar makes life so much easier.

(I know e-lisp is not supposed to be like lisp - but old habits die
hard.)

2: setenv

I was writing some code - and I needed to change the environment of
emacs just before starting a new sub-process. I found the function
getenv - but the partner setenv just did not seem to exist!!

A quick perusal of the variables gave me process-environment - a list
of environment strings which will be used by subprocesses.

It seemed silly not to have a setenv so I wrote one myself.
Notice how the apply/mapcar/or/lambda function makes life so much harder!
I would appreciate knowledgable insights into modifications to make
the code more elegant.

;;------ Cut here 8< --------------------------------------------------

(defun setenv (name new)
  (cond ((<= 1 (apply '+ (mapcar 'env-entry process-environment)))
	;;The process-environment list contains the name - therefore
	;;change it to the new value
	 (setq proccess-environment (mapcar 'change-env
					    process-environment)))
	(t 
	;;Otherwise just append the new setting to the front of the list.
	 (setq process-environment
		 (append (list (format "%s=%s" name new))
			 process-environment)))))

(defun change-env (str)
    ;;Return the new setting of the environment if str contains the
    ;;old setting, otherwise just returning str.
    (cond ((= 1 (env-entry str))
	   (format "%s=%s" name new))
	  (t str)))

(defun env-entry (entry)
    ;;Does entry contain the environment variable name?
    ;;Return 1 if it does - 0 otherwise
  (let ((match (string-match (format "%s=" name) entry)))
    (cond ((null match) 0)
	  ((= match 0) 1)
	  (t 0))))

;;----------------------------------------------------------------------

	Thanks for your time, 

--
NAME : H J "Max" Thompson -  So called for I Max And Xian.
SNAIL: Department Of Computer Science, Warwick University, CV4 7AL, ENGLAND.
JANET: max@cs.warwick.ac.uk               UUCP: {uunet,mcvax}!ukc!warwick!max
JOKE : "Waiter there's a fly in my soup!" "Sir, Its a feature not a bug!"

wjc@ho5cad.ATT.COM (Bill Carpenter) (06/02/89)

In article <CSUWN.89Jun2041413@orchid.warwick.ac.uk> csuwn@cu.warwick.ac.uk (Max) writes:
> I was writing some code - and I needed to change the environment of
> emacs just before starting a new sub-process. I found the function
> getenv - but the partner setenv just did not seem to exist!!

The availability of "setenv" is a compile-time option.  To get it,
make sure you have "#define MAINTAIN_ENVIRONMENT" in the config.h
stuff.  I can't think of a good reason to leave this out, but someone
must have, since it is not the default.
--
   Bill Carpenter         att!ho5cad!wjc  or  attmail!bill

Duchier-Denys@cs.yale.edu (Denys Duchier) (06/02/89)

(defun reduce (fun val lst)
  (while lst (setq val (funcall fun cal (car lst)) lst (cdr lst)))
  val)

(reduce (function (lambda (x y) (or x y))) (mapcar <your-function> <your-list>))

(reduce '* 1 '(1 2 3 4 5)) => 120 ;(i.e. 5!)

Also check cl.el for functions: some, every, notany, notevery

if <your-function> has no side effects: (some <your-function> <your-list>)

you need to define MAINTAIN_ENVIRONMENT in order to get all the
environment goodies like setenv.

--Denys

kanderso@DINO.BBN.COM (06/02/89)

In most lisps you can't apply things like 'or or 'and because the are special
forms, not functions.  Here is a recursive function that may do what
you want.  you could also use while.

(defun setenv (name new environment)
  (if (null environment) environment
      (if (= (string-match (format "%s=" name) (car environment)) 0)
	  (cons (format "%s=%s" name new) (cdr environment))
	  (cons (car environment) (setenv name new (cdr environment))))))

jr@bbn.com (John Robinson) (06/03/89)

In article <62353@yale-celray.yale.UUCP>, Duchier-Denys@cs (Denys Duchier) writes:
>(defun reduce (fun val lst)
>  (while lst (setq val (funcall fun cal (car lst)) lst (cdr lst)))
>  val)
>
>(reduce (function (lambda (x y) (or x y))) (mapcar <your-function> <your-list>))
>
>(reduce '* 1 '(1 2 3 4 5)) => 120 ;(i.e. 5!)

Unfortunately, funcall also works only with functions, not subr's:

  (reduce 'or nil '(nil t nil)) => error "Invalid function #<subr or>"

Eval, on the other hand, is happy with subrs.  Hence,

(defun reduce (fun val lst)
  (while lst (setq val (eval (list fun val (car lst))) lst (cdr lst)))
  val)

then,

  (reduce 'or nil '(nil t nil)) => t

and, to make some examples from the original query,

  (apply (function (lambda (lst) (eval (cons 'or lst))))
         (list (mapcar (function (lambda (elem) (string-match "^TERM=" elem)))
                       process-environment)))

      => 0 (if TERM is in process-environment), else nil.

Now, some might complain that eval is too messy...
--
/jr, nee John Robinson   What a waste it is to lose one's mind--or not
jr@bbn.com or bbn!jr      to have a mind.  How true that is. -Dan Quayle

jr@bbn.com (John Robinson) (06/06/89)

In article <40844@bbn.COM>, I write:
>Unfortunately, funcall also works only with functions, not subr's:
>
>  (reduce 'or nil '(nil t nil)) => error "Invalid function #<subr or>"

Kyle Jones pointed out in mail that this statement should read:

  Unfortunately, funcall doesn't work either with forms that don't
  eval their arguments, e.g. and, or, cond.
--
/jr, nee John Robinson   What a waste it is to lose one's mind--or not
jr@bbn.com or bbn!jr      to have a mind.  How true that is. -Dan Quayle