5

So I am trying to learn R on my own and am just working through the online tutorial. I am trying to code a recursive function that prints the first n terms of the Fibonacci sequence and can't get the code to run without the error:

Error in if (nterms <= 0) { : missing value where TRUE/FALSE needed

My code does ask me for input before entering the if else statement either which I think is odd as well. Below is my code any help is appreciated.

#Define the fibonacci sequence

recurse_fibonacci <- function(n) {
    # Define the initial two values of the sequence

    if (n <= 1){
        return(n)
    } else {

    # define the rest of the terms of the sequence using recursion
    return(recurse_fibonacci(n-1) + recurse_fibonacci(n-2))
    }
}

#Take input from the user
nterms = as.integer(readline(prompt="How many terms? "))

# check to see if the number of terms entered is valid
if(nterms <= 0) {
    print("please enter a positive integer")
} else {

    # This part actually calculates and displays the first n terms of the sequence
    print("Fibonacci Sequence: ")
    for(i in 0:(nterms - 1)){
        print(recurse_fibonacci(i))
    }
}
phoxis
  • 60,131
  • 14
  • 81
  • 117
apr92
  • 51
  • 2
  • 1
    Sorry apr92 but I cannot replicate any problems. The example works fine on my system. – Jan Jun 01 '20 at 22:28
  • 1
    If I copy-paste his entire code chunk into my console, I get a similar error, presumably because what's pasted immediately after the `readline` command is interpreted as (an invalid) `nterms`. – infinitefactors Jun 01 '20 at 22:30
  • 1
    The error mentioned by op happens only if you copy and paste the relevant code to the terminal. – kangaroo_cliff Jun 01 '20 at 22:30
  • Really? Because this is the second time I have gotten errors that others don't get. I was told the first time to highlight the whole code then hit run which fixed it that time but didn't help this time. What system are you using? – apr92 Jun 01 '20 at 22:31
  • 1
    @apr92 If you simply run this code from the RStudio environment or any text editor, instead of copy-pasting into the command line or console, it should work. – infinitefactors Jun 01 '20 at 22:31
  • R4.0.0 on Ubuntu 20.04. No erros here. And I have copy-pasted the code into RStudio. This should also work on RGui/Windows. – Rui Barradas Jun 01 '20 at 22:32
  • 1
    Save the code in file, `fib.R`, then from an R shell you can do `source ("fib.R")` – phoxis Jun 01 '20 at 22:33
  • infinitefactors: Do you know why it would interpret nterms. as invalid? especially when I was not asked to input a number when i hit run? – apr92 Jun 01 '20 at 22:33
  • @phoxis `Rscript fib.R` gives the error in the question. – Rui Barradas Jun 01 '20 at 22:35
  • 1
    As soon as the line defining `nterms` is executed, the expression that comes immediately after will be assigned to `nterms`. So if you copy-paste that whole thing in one go, it'll think that whatever line comes after that is `nterms` -- it won't "wait" for you to supply a valid `nterms` before running the rest of the code. – infinitefactors Jun 01 '20 at 22:35
  • I tried it in RStudio but got the same error. I typed the code in notepad and opened that in RStudio but no luck either. – apr92 Jun 01 '20 at 22:36
  • but if the line defining nterms is executed shouldnt it prompt me for input before moving on? – apr92 Jun 01 '20 at 22:39

3 Answers3

2

To make it work with Rscript replace

nterms = as.integer(readline(prompt="How many terms? "))

with

cat ("How many terms?")
nterms = as.integer (readLines ("stdin", n = 1))

Then you can run it as Rscript fib.R, assuming that the code is in the file fib.R in the current working directory.

Otherwise, execute it with source ("fib.R") within an R shell.

Rscript does not operate in interactive mode and does not expect any input from the terminal. Check what interactive () returns in both the cases. Rscript will return FALSE as it is non-interactive, but the same function when run within an R shell (with source ()) it will be true.

?readline mentions that it cannot be used in non-interactive mode. Whereas readLines explicitely connect to stdin.

phoxis
  • 60,131
  • 14
  • 81
  • 117
2

This is a problem of readline in non-interactive mode. readline does not wait for a keypress and immediately executes the next instruction. The solution below is the solution posted in this other SO post.

I post below a complete answer, with the Fibonnaci numbers function a bit modified.

recurse_fibonacci <- function(n) {
  # Define the initial two values of the sequence
  if (n <= 1){
    n
  } else{
    # define the rest of the terms of the sequence using recursion
    Recall(n - 1) + Recall(n - 2)
  }
}

#Take input from the user
cat("How many terms?\n")
repeat{
  nterms <- scan("stdin", what = character(), n = 1)
  if(nchar(nterms) > 0) break
}
nterms <- as.integer(nterms)

# check to see if the number of terms entered is valid
if(nterms <= 0) {
  print("please enter a positive integer")
} else {
  # This part actually calculates and displays the first n terms of the sequence
  print("Fibonacci Sequence: ")
  for(i in 0:(nterms - 1)){
    print(recurse_fibonacci(i))
  }
}

This code is the contents of file fib.R. Running in a Ubuntu 20.04 terminal gives

rui@rui:~$ Rscript fib.R
How many terms?
8
Read 1 item
[1] "Fibonacci Sequence: "
[1] 0
[1] 1
[1] 1
[1] 2
[1] 3
[1] 5
[1] 8
[1] 13
rui@rui:~$
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • Thanks for the help. The error is gone however now there is a new problem: below the script in console it does display all the code and after the cat() it does ask for me to input a number but then it just moves on to the repeat loop and never seems to leave it which im pretty sure means theres some kind of infinite loop. Like I said I am typing everything in notepad and then running it in RStudio, don't know if that makes a difference of not. I'm very new to this so sorry for the burden – apr92 Jun 01 '20 at 23:37
  • update: hitting the source button only displays the message "How many terms?" but when I hit 8 it does not print the terms of the sequence – apr92 Jun 01 '20 at 23:40
  • @apr92 Try removing the code lines `repeat` and `if(nchar(...))`. – Rui Barradas Jun 02 '20 at 07:56
  • ok I got it to work but I did have to change a couple of things from your code. Instead of using recall() like you did I stuck with return. I changed nterms = as.integer(readline("stdin", n = 1)) to nterms = as.integer(readline()) and i changed the counter in the for loop from 0:(nterms-1) to 0:(nterms) and now it works. I do have some questions about this though like why did you chose to use cat() instead of readline (), why did you chose to use recal instead of return, and in cat("How many terms?\n") why do you have the "\n"? Thanks again – apr92 Jun 03 '20 at 15:33
  • @apr92 1) `cat` gives a nicer output, with no `[1]`. The final `\n` is the newline character. 2) `scan` is used instead of `readline` because R sends an empty `""` string to `readline` automatically without waiting for user input and executes the next instruction. `scan` can read from `stdin` and has an argument `n` where you can pass the number of input values to be read. – Rui Barradas Jun 03 '20 at 16:21
  • @apr92 3) There is no need for `return` since the function can return `n` or call itself recursively returning those values. `Recall` does precisely that and it seemed more readable to me. But if your code works, use it. – Rui Barradas Jun 03 '20 at 16:24
0

The code works fine but you shouldn't enter it into the terminal as is. My suggestion: put the code into a script file (ending .R) and source it (get help about it with ?source but it's actually pretty straightforward).

In R-Studio you can simply hit the source button.

Jan
  • 4,974
  • 3
  • 26
  • 43