So I am very new to Racket (and functional programming) but I am having an issue with putting a cond statement in a for loop. I would like to add more conditions to identify characters in a string. Here is what I'm working with right now.
(define (check i)
(cond [(member i '("(" ")" "+" "-" "*" "/")
)
i]
[(eqv? i "1") "yes"]))
With the above function (check "1") will return "yes" and "(check "+")" will return "+". However if I add a for loop, like below, "(check "1")" and "(check "+") will return void.
(define (check n)
(for ([i (in-string n)])
(cond [(member i '("(" ")" "+" "-" "*" "/")
)
i]
[(eqv? i "1") "yes"])))
Can anyone clarify why the for loop has this effect? I have tried alternative methods and I've tried to understand why this happens but I just can't get anywhere.
Thanks
Related
I am trying to create a dictionary or hash-table where keys are string and values are integers with following code:
(define dict #())
(dict-set! dict "bash" 1)
(displayln dict)
(dict-set! dict "racket" 1)
(displayln dict)
However, it gives following error:
dict-set!: contract violation
expected: (dict-implements/c dict-set!)
given: '#()
in: the d argument of
(->i
((d (dict-implements/c dict-set!))
(k (d) (dict-key-contract d))
(value (d) (dict-value-contract d)))
(_r void?))
contract from: <collects>/racket/dict.rkt
Where is the problem and how can it be solved?
The problem is that the literal #() is an empty vector.
To make a mutable hash table, use (make-hash).
(define dict (make-hash))
I have just started coding in SMLNJ and have been having some trouble making a program that returns a string in a triangular star pattern. For example triangle(5) should output:
*****
****
***
**
*
My code so far is:
fun triangle(x) =
if (x = 0) then "\n"
else
let
fun makeTriangle(n) =
if(n = 0) then "\n" else "*"^makeTriangle(n-1);
in
makeTriangle(x);
end
triangle(x-1)
I am getting the error "triangle.sml:9.3 Error: syntax error: inserting EQUALOP". Any help would be appreciated.
There are at least two issues with your code:
First, there is a simple operator precedence issue:
if(n = 0) then "\n" else "*"^makeTriangle(n-1)
parses as
(if(n = 0) then "\n" else "*") ^ makeTriangle(n-1)
rather than your intended
if(n = 0) then "\n" else ("*" ^ makeTriangle(n-1))
The solution is to put in the needed parentheses.
Another issue is the stray line triangle(x-1) at the bottom of the function. It is unrelated to the code above it. If your intention is to concatenate it to the result of the function call makeTriangle(x) then you would need to do the explicit concatenation. There really shouldn't be anything in your function definition after the end since that end terminates the else part.
A minor issue: since your function makeTriangle inserts "\n", your code (after fixed) will have two "\n" at the bottom of the triangle. If that isn't what you want, perhaps you can think about the basis case (n=0).
Since John already explained some of the issues with your code, and since this seems like an exercise, here are two ways you could solve it differently:
Recursively, using pattern matching:
fun repeat (0, _) = []
| repeat (n, x) = x :: repeat (n-1, x)
fun triangle 0 = ""
| triangle n = implode (repeat (n, #"*")) ^ "\n" ^ triangle (n-1)
There's a library function called List.tabulate of which repeat is a special case:
fun repeat (n, x) = List.tabulate (n, fn _ => x)
But actually, triangle itself fits pretty well within List.tabulate:
fun triangle n =
concat (List.tabulate (n, fn i => implode (repeat (15 - i, #"*")) ^ "\n"))
I have the following code:
let rec f n =
if n < 10 then "f" + g (n+1) else "f"
and g n =
if n < 10 then "g" + f (n+1) else "g"
I want to make these mutually recursive functions tail recursive for optimization.
I have tried the following :
let rec fT n =
let rec loop a =
if n < 10 then "f" + gT (a) else "f"
loop (n + 1)
and gT n =
let rec loop a =
if n < 10 then "g" + fT (a) else "g"
loop (n + 1)
Is that a correct tail recursive version? If no, a hint in the right direction would be greatly appreciated.
EDIT (Second take on a solution):
let rec fA n =
let rec loop n a =
if n < 10 then loop (n + 1) ("f" + a) else a
loop n "f"
and gA n =
let rec loop n a =
if n < 10 then loop (n + 1) ("g" + a) else a
loop n "g"
EDIT (Third take on a solution):
let rec fA n a =
if n < 10 then gA (n + 1) (a + "f") else a
and gA n a =
if n < 10 then fA (n + 1) (a + "g") else a
EDIT (The correct solution):
let rec fA n a =
if n < 10 then gA (n + 1) (a + "f") else (a + "f")
and gA n a =
if n < 10 then fA (n + 1) (a + "g") else (a + "g")
Your solution is most definitely not tail-recursive.
"Tail-recursion" is such recursion where every recursive call is the last thing that the function does. This concept is important, because it means that the runtime can opt out of keeping a stack frame between the calls: since the recursive call is the very last thing, and the calling function doesn't need to do anything else after that, the runtime can skip returning control to the calling function, and have the called function return right to the top-level caller. This allows for expressing recursive algorithms of arbitrary depth without fear of running out of stack space.
In your implementation, however, the function fT.loop calls function gT, and then prepends "f" to whatever gT returned. This prepending of "f" happens after gT has returned, and therefore the call to gT is not the last thing that fT.loop does. Ergo, it is not tail-recursive.
In order to convert "regular" recursion into the "tail" kind, you have to "turn the logic inside out", so to speak. Let's look at the function f: it calls g and then prepends "f" to whatever g returned. This "f" prefix is the whole "contribution" of function f in the total computation. Now, if we want tail recursion, it means we can't make the "contribution" after the recursive call. This means that the contribution has to happen before. But if we do the contribution before the call and don't do anything after, then how do we avoid losing that contribution? The only way is to pass the contribution into the recursive call as argument.
This is the general idea behind tail-recursive computation: instead of waiting for the nested call to complete and then adding something to the output, we do the adding first and pass what has been "added so far" into the recursive call.
Going back to your specific example: since the contribution of f is the "f" character, it needs to add this character to what has been computed "so far" and pass that into the recursive call, which will then do the same, and so on. The "so far" argument should have the semantics of "compute whatever you were going to compute, and then prepend my 'so far' to that".
Since you've only asked for a "hint", and this is obviously homework (forgive me if I'm wrong), I am not going to post the actual code. Let me know if you'd rather I did.
I second the observation that your attempt definitely does not put the recursion in tail position
How I would handle moving the recursion into tail position would be using a continuation. To do so, we'd have to implement fk and gk variants which have a continuation parameter, then f and g can be implemented using fk and gk respectively
I'm not an F# expert, but I can illustrate this quite simply with JavaScript. I wouldn't ordinarily post an answer using a different language, but since the syntax is so similar, I think it will be helpful to you. It also has the added benefit that you can run this answer in the browser to see it working
// f helper
let fk = (n, k) => {
if (n < 10)
return gk(n + 1, g => k("f" + g))
else
return k("f")
}
// g helper
let gk = (n, k) => {
if (n < 10)
return fk(n + 1, f => k("g" + f))
else
return k("g")
}
let f = n =>
fk(n, x => x)
let g = n =>
gk(n, x => x)
console.log(f(0)) // fgfgfgfgfgf
console.log(g(0)) // gfgfgfgfgfg
console.log(f(5)) // fgfgfg
console.log(g(5)) // gfgfgf
console.log(f(11)) // f
console.log(g(11)) // g
Using the file "test-lexer.lisp", I have very slightly modified lex to be
(defparameter *lex* (test-lexer "{ 1.0 12 fred 10.23e12"))
and increased the number of times test repeats to 6
(defun test ()
(loop repeat 6
collect (multiple-value-list (funcall *lex*))))
and tried modifying test-lexer in a number of ways to try to get it to recognize "{" as a token.
For example, adding [:punct:] in (deflexer test-lexer ...)
by changing
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
to
("[:alpha:][:alnum:][:punct:]*"
(return (values 'name %0)))
and consistently get errors like
"""Lexer unable to recognize a token in "{ 1.0 12 fred 10.23e12", position 0 ("{ 1.0 12 fred 10.23e")
[Condition of type SIMPLE-ERROR]"""
How can i specify "{" as a character to be recognized? Or is my problem elsewhere?
The cl-lexer system is based on regular expressions, so you can put any literal character to stand for itself, like {. But it happens that the brace character has a special meaning in the regular expression language, so you need to quote it with a backslash. In order to write a backslash in Lisp strings, backslashes need to be escaped. Hence:
(deflexer test-lexer
("\\{" (return (values :grouping :open-brace))) ;; <-- Here
("[0-9]+([.][0-9]+([Ee][0-9]+)?)"
(return (values 'flt (num %0))))
("[0-9]+"
(return (values 'int (int %0))))
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
("[:space:]+"))
I return the :open-brace value and the :grouping category, but you can choose to return something else if you want.
The test function then returns:
((:GROUPING :OPEN-BRACE) (FLT 1.0) (INT 12)
(NAME "fred") (FLT 1.023e13) (NIL NIL))
I'm unable to print the return value of return-str.
; return-str.lisp
(defun ask-for-input(str)
(princ str)
(let ((cmd (read-line)))
cmd))
(defun return-str()
(let ((data-str (ask-for-input "enter a string")))
(data-str)))
(princ return-str)
Executing the code above with clisp, I got:
$ clisp return-str.lisp
*** - EVAL: variable RETURN-STR has no value
Please help me on how to properly return a string from return-str.
Thank you.
Your parentheses are incorrect in a couple of places.
(data-str) should be replaced with data-str because data-str is not a function.
(princ return-str) should be replaced with (princ (return-str)) because return-str is a function.