Newbie needs help please

Discussion of Common Lisp
RaydPanda
Posts: 8
Joined: Thu Oct 22, 2009 11:13 am
Location: Bergen, Norway

Newbie needs help please

Post by RaydPanda » Thu Oct 29, 2009 12:01 pm

Hello all,

I am a big LISP-Newb and am struggling with a program that is supposed to encrypt a string with Caesar's cipher. What I have in mind is a function that takes in 2 arguments: a string and a number to specify the modulus. Something along the lines:

(defun c-encrypt (string number)
("lots of helper functions"))

My thoughts so far are that it would be best to set the alphabet as a parameter and write a function that looks up a chars position in the parameter and then shifts it the wanted Caesar's modulo to the right e.g. A ->modulo 7 -> H

May look something along the lines:

(defun shift (char x) (char *alphabet* (mod(+24 x"being the wanted modulo")27)))

Well, I ran headfirst into a lot of problems. First of all, I can not find a function to split a string into its single chars (convert it to numbers fine, but simply split it...). If I could somehow split the string into its single characters and make a list out of them my first problem would be solved. When trying to concatenate there are always these darn #\ left which make it impossible to use the parameter.

As you see I already fail at the first obstacle of the whole project... :oops: Not to speak about the rest...

Any help would be greatly appreciated since I really start to get frustrated about this project and LISP itself. For some reason I find it extremely difficult to "think LISP".

Thanks already for your answers!

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Newbie needs help please

Post by ramarren » Thu Oct 29, 2009 12:59 pm

RaydPanda wrote:I am a big LISP-Newb
First, the language family is called Lisp, and hasn't been called LISP since the, I believe, seventies, when non-capital letters were invented ;-)
RaydPanda wrote:First of all, I can not find a function to split a string into its single chars (convert it to numbers fine, but simply split it...).
That is meaningless. A string is a sequence of characters. It is already as split as it is going to be. All functions in sequences dictionary work on strings. For this application you do not want the list anyway, a vector and hash-table (in theory you could o it without the lookup by manipulating char-codes, but this is not general) is better.

sinnatagg
Posts: 29
Joined: Tue Apr 21, 2009 3:04 am

Re: Newbie needs help please

Post by sinnatagg » Sat Oct 31, 2009 2:38 am

RaydPanda wrote: Well, I ran headfirst into a lot of problems. First of all, I can not find a function to split a string into its single chars (convert it to numbers fine, but simply split it...). If I could somehow split the string into its single characters and make a list out of them my first problem would be solved. When trying to concatenate there are always these darn #\ left which make it impossible to use the parameter.
Quick and dirty:

Code: Select all

> (loop for c across "foo" collect c)
(#\f #\o #\o)
> (coerce * 'string)
"foo"
-a

RaydPanda
Posts: 8
Joined: Thu Oct 22, 2009 11:13 am
Location: Bergen, Norway

Re: Newbie needs help please

Post by RaydPanda » Sun Nov 01, 2009 7:11 am

Thanks for your posts!

@Ramarren

Well, I guess my university course is not the best since I wasn't told about sequences and my teachers use "LISP" as if it is the correct form... thanks for the enlightenment! I'll try my luck with these, maybe I get some results. :)

@sinnatag

My problem with the first of your suggestions is that I need a list without the #\, otherwise I can not work with my alphabet parameter. Any suggestions on that?

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Newbie needs help please

Post by ramarren » Sun Nov 01, 2009 8:27 am

RaydPanda wrote:@Ramarren

Well, I guess my university course is not the best since I wasn't told about sequences and my teachers use "LISP" as if it is the correct form... thanks for the enlightenment! I'll try my luck with these, maybe I get some results. :)
Unfortunately many teachers learnt Lisp when it was still a LISP and refused to learn anything more than necessary for their assignments to actually work in modern Lisp. Sometimes.
RaydPanda wrote:@sinnatag

My problem with the first of your suggestions is that I need a list without the #\, otherwise I can not work with my alphabet parameter. Any suggestions on that?
#\ is just syntax for characters. A string is a sequence of characters. Your alphabet should be a sequence of characters. It will work. If it doesn't work, then you are doing it wrong.

For the Caesar's cipher you need to look up the source characters position in the alphabet, add to it the shift modulo the length of the alphabet and then get the character from the alphabet. This can be done character by character.

sinnatagg
Posts: 29
Joined: Tue Apr 21, 2009 3:04 am

Re: Newbie needs help please

Post by sinnatagg » Sun Nov 01, 2009 8:41 am

RaydPanda wrote: My problem with the first of your suggestions is that I need a list without the #\, otherwise I can not work with my alphabet parameter. Any suggestions on that?
You can convert characters to symbols with something like this:

Code: Select all

(intern (make-string 1 :initial-element (char-upcase #\a)))
For a real program this would just be making things difficult for yourself, but hopefully it will let you return to your assignment (which probably expects a solution based on lists and symbols or somesuch).

-a

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: Newbie needs help please

Post by gugamilare » Sun Nov 01, 2009 7:15 pm

sinnatagg wrote:
RaydPanda wrote: My problem with the first of your suggestions is that I need a list without the #\, otherwise I can not work with my alphabet parameter. Any suggestions on that?
You can convert characters to symbols with something like this:

Code: Select all

(intern (make-string 1 :initial-element (char-upcase #\a)))
This way is simpler:

Code: Select all

(intern (string (char-upcase #\a)))

sinnatagg
Posts: 29
Joined: Tue Apr 21, 2009 3:04 am

Re: Newbie needs help please

Post by sinnatagg » Sun Nov 01, 2009 10:46 pm

gugamilare wrote: This way is simpler:
Yeah, I was kind of wondering why there wasn't a function like this in CL, aside from coerce() which doesn't work for this case.

-a

RaydPanda
Posts: 8
Joined: Thu Oct 22, 2009 11:13 am
Location: Bergen, Norway

Re: Newbie needs help please

Post by RaydPanda » Mon Nov 02, 2009 12:10 pm

First off, thanks to all of you!

By now I got far enough to encrypt a single character. I try now to get it working on a string but to no avail so far.
The code I have until now looks like this:

Code: Select all

; Alphabet as parameter plus one whitespace at index 0

(defparameter *alphabet* " abcdefghijklmnopqrstuvwxyz,.0123456789")

; Finds the index of char in  *alphabet*:

(defun alphabet-index (char)
  (position char *alphabet*))
 
; Finds the char shifted n places to the right in the alphabet:

(defun rotate (char n)
  (elt *alphabet* (mod (+ (alphabet-index char) n)(length *alphabet*))))
I am not sure how to use the map function with this. I tried (map 'string #rotate) but that doesn't seem to be the correct method. How do I get my rotate function to work on a whole string?

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Newbie needs help please

Post by ramarren » Mon Nov 02, 2009 12:50 pm

RaydPanda wrote:I am not sure how to use the map function with this. I tried (map 'string #rotate) but that doesn't seem to be the correct method. How do I get my rotate function to work on a whole string?
The signature of the map function is:

Code: Select all

map result-type function &rest sequences+ => result
which, for this case, means you first need a function of one argument, the character, since you only have one sequence to be mapped, the encrypted string. This can be made using lambda, like this (the "#'" here is really optional, but I like it as a marker that a function is created here):

Code: Select all

(defun make-rotator (n)
  #'(lambda (char)
      (rotate char n)))
This defines a function returning a closure, because the shift argument is closed over. You could also just use lambda directly in the map form, but I think this is clearer.

Then you can simply use that closure as an argument to map:

Code: Select all

CL-USER> (map 'string (make-rotator 5) "ala ma kota")
"fqferfeptyf"

Post Reply