Alter REPL to display username, hostname and current working directory? - scheme

In Guile's REPL the prompt is scheme#(guile-user)>, but I want it to show my-name#hostname(current-working-directory)>. Is there a way to do this?

IN system/repl/common in the guile scheme distribution you can see the repl-prompt implementation:
(define (repl-prompt repl)
(cond
((repl-option-ref repl 'prompt)
=> (lambda (prompt) (prompt repl)))
(else
(format #f "~A#~A~A> " (language-name (repl-language repl))
(module-name (current-module))
(let ((level (length (cond
((fluid-ref *repl-stack*) => cdr)
(else '())))))
(if (zero? level) "" (format #f " [~a]" level)))))))
This indicates that you have a repl option 'prompt which is a lambda
(lambda (repl) ...)
(But it can also be a simple string) Than can outputs anything you want.
You have,
https://www.gnu.org/software/guile/manual/html_node/System-Commands.html#System-Commands
so you can do
scheme#(guile-user)> ,option prompt ">"
>
>(+ 1 2)
$1 = 3
>,option prompt (lambda (repl) ">>")
>>(+ 2 3)
$2 = 5
>>
But what to do if you want to add the prompt in your .guile file?
If you put these inside .guile (before the prompt is created)
(use-modules (system repl common))
(repl-default-option-set! 'prompt ">>>")
you will get
>>> (+ 1 2)
3
You can create new repls as well, but that's for another question
For your specific example you can try
> ,option prompt (lambda (repl)
(format #f "~a#~a(~a)>"
(getenv "USER")
(vector-ref (uname) 1)
(getcwd)))
(but on one line) and get
stis#lapwine(/home/stis/src/guile/module/system/repl)> (+ 1 2)
3
Hope that this helps.

Related

User input to a list

I'm trying to take in user input and add it to a list but I have not been able to get it working. I'm still new to scheme and have been browsing around to try to figure it out but I haven't had any luck.
(display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(define (intlist number)
(define number(read-line))
(cond (number? number)
(cons lst (number))
(else
(display lst)
done')))
this is what I have so far. Any help or direction to where I can learn a bit more is appreciated.
Your solution is almost correct, but it doesn't work, because:
Variable lst doesn't exist and with this expression (number), you are calling some undefined function number.
done' is badly written 'done.
Function cons expects element as first argument and other element or list as second argument.
See these examples:
> (cons 1 2)
'(1 . 2)
> (cons 1 '())
'(1)
> (cons 1 (cons 2 (cons 3 '())))
'(1 2 3)
Last example is important here- your function will be recursive and it will return a cons cell in each step. If I will follow your solution, this can be enough:
(define (list-from-user)
(let ((number (read)))
(if (number? number)
(cons number (list-from-user))
'())))
(Note that I used read instead of read-line, because read-line returns string, and let instead of define.)
If you really want to wait for e, you must decide, what happens if user enters something that isn't number and isn't e- maybe just ignore it?
(define (list-from-user)
(let ((user-input (read)))
(cond ((number? user-input) (cons user-input (list-from-user)))
((eq? user-input 'e) '())
(else (list-from-user)))))
Then just add some wrapping function with output:
(define (my-fn)
(begin (display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(list-from-user)))
and call it
> (my-fn)
Note that my function returns list with numbers, instead of some useless 'done, so I can use that function in other functions.
(define (sum-of-list)
(let ((lst (my-fn)))
(format "Sum of given list is ~a." (apply + lst))))
> (sum-of-list)

Printing intermediate results in Scheme

I want to make a program that makes a conversion simulating a for loop, for example:
orig value converted
1 2.2
2 4.4
...
199 437.8
So far, what I have done is the following:
(define (conv ini)
(if (> ini 199)
0
(begin(
(display (* ini 2.2))
(newline)
(conv (+ ini 1))))))
but when I want to run it I got the following error:
arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 2
arguments...:
I see that my recursion call is fine, so I cannot get it which one is the problem.
The syntax of begin is (begin form ...) not (begin (form ...)): your function should be
(define (conv ini)
(if (> ini 199)
0
(begin
(display (* ini 2.2))
(newline)
(conv (+ ini 1)))))
(Or, if you are enamoured of a syntax like that, you could define
(define-syntax beguine
(syntax-rules ()
[(_ (form ...))
(begin form ...)]))
and then (beguine (...)) will work.)
...
(begin(
(display (* ini 2.2))
...))))
In your code you actually try to execute (OP ...), where OP is the value of (display ...), which for sure is not a function.
So I doubt a lot your output is the output of what you pasted in your question.

Previous result in Chez Scheme

In the Chez Scheme REPL, is it possible to get the previous result? For example in ruby's irb repl, underscore can be used.
For example can I do the following?
> (+ 2 3)
5
> (+ 1 <something>)
And get 6?
Chez Scheme does not have a built in way to do this, but being scheme, we can roll our own:
(define repl
(let ([n 1])
(lambda (expr)
(let-values ([vals (eval expr)])
(for-each (lambda (v)
(unless (eq? (void) v)
(let ([sym (string->symbol (format "$~a" n))])
(set! n (+ n 1))
(printf "~a = " sym)
(pretty-print v)
(set-top-level-value! sym v))))
vals)))))
(new-cafe repl)
repl is now a function that takes an expression, evaluates it, stores the non-void results into ids of the form $N where N is monotonically increasing, and prints out the results. new-cafe is a standard chez function that manages the Reading, Printing, and Looping parts of REPL. It takes a function that manages the Evaluation part. In this case, repl also needs to manage printing since it shows the ids associated with the values.
Edit:
I found a slightly better way to do this. Instead of having a custom repl, we can customize only the printer. Now this function is no longer responsible for also evaluating the input.
(define write-and-store
(let ([n 1])
(lambda (x)
(unless (eq? (void) x)
(let ([sym (string->symbol (format "$~a" n))])
(set! n (+ n 1))
(set-top-level-value! sym x)
(printf "~a = " sym)
(pretty-print x)
(flush-output-port (console-output-port)))))))
(waiter-write write-and-store)
A simple usage example:
> (values 1 2 3 4)
$1 = 1
$2 = 2
$3 = 3
$4 = 4
> (+ $1 $2 $3 $4)
$5 = 10

How does the console output determined

I'm fairly new to Scheme and I'm using DrRacket as my IDE.
If i have a small program, for example - a program that's given a number, would generate a list from 0 to that number:
(define (helper num mylist)
(cond [(zero? num) (append (list 0) mylist)]
[else (helper (- num 1) (append (list num) mylist))]))
(define (genlist num)
(helper num '()))
(genlist 10) => '(0 1 2 3 4 5 6 7 8 9 10)
I'm coming from a Java background, and there is obviously no print statement here. So how does it "decide" to output mylist to the console? What "tells" it to do so?
genlist doesn't print the list, it only returns it. It's the REPL that prints it because it prints the return value of whichever expression you enter.
It also prints the values of any non-void expressions that are written at the top level of your file when you load it.
The interpreter (REPL) always prints the value of the expression you entered.
If we define
(define (foo a)
(display a)
a)
(define (bar a)
(display a))
we get the output
> (bar "hello")
hello
> (foo "hello")
hello"hello"
where the hellos (without quotation marks) are output by the procedures, and then the REPL prints the result of the procedure calls, which is nothing for the first, and "hello" for the second.
In DrRacket, the outputs also have different colours.
(Also note that a string that is a value is printed differently from a string that is a procedure's output.)

I need a function to display an 'unprocessed' expression

I am new to Scheme so excuse me if I am using the wrong vocabulary. I want a function, I am calling it QandA, that will (among other things) display its raw or unprocessed argument. For example:
(QandA (+ 1 2)) should return the string "(+ 1 2) : 3"
(QandA (quote (+ 1 2))) should return "(quote (+ 1 2)) : (+ 1 2)"
What I first tried was:
(define (QandA x)
(display (quote x)) (display " : " ) (display x))
but then
(QandA (+ 1 2)) returns "x : 3"
I understand why this is wrong, but don't know where to look to find a solution.
So the question is, what do I replace (display (quote x)) with to get the behavior I require. Any hints welcome.
As #ymonad pointed out, this is a good scenario for using macros - because you need to defer the evaluation of the expression that's passed as parameter to QandA. Some of your previous questions were tagged racket, so here's an implementation for Racket using #lang racket (also works for #lang scheme) that returns a string, as requested (if you want to display the value replace format with printf):
(define-syntax-rule (QandA exp)
(format "~a : ~a" 'exp exp))
This is the output for the sample input given in the question:
(QandA (+ 1 2))
=> "(+ 1 2) : 3"
(QandA (quote (+ 1 2)))
=> "(quote (+ 1 2)) : (+ 1 2)"
As you see, you cannot achieve it using function since the argument is evaluated before it is passed to the function.
One solution is using macros, it can access to the unprocessed expression and create another expression.
Here's an example that works on guile
(define-syntax QandA
(syntax-rules ()
((QandA arg)
(begin (display (quote arg))(display " : ")(display arg)))))
(QandA ((+ 1 2))) ; (+ 1 2) : 3
(QandA (quote (+ 1 2))) ; (quote (+ 1 2)) : (+ 1 2)
The supported syntax of generating macro differs by interpreters, so you should check the document of interpreter which you are using.
However, define-syntax and syntax-rules should be able to use in interpreter which supports R5RS or R6RS.

Resources