Calculation of mortgage repayments I've just started learning R, but I feel that I'm using it only as a normal procedural language without taking advantage of some built-in functions and data structures.

I wrote a function that calculates repayments for mortgage with an option of specifying list of overpayments to reduce monthly payments.  Please suggest any improvements on making it more native to R.

source("http://pastebin.com/raw.php?i=q7tyiEmM") ## for pmt()
mortgage &lt;- function(price=1000000, deposit=0.10, rate=0.04, years=25, over=c()) {
    loan &lt;- price - price * deposit
    months &lt;- years * 12
    capital &lt;- c()
    interest &lt;- c()
    payments &lt;- c()
    currentCapital &lt;- loan
    monthlyRate &lt;- rate / 12
    payment &lt;- -pmt(monthlyRate, nper = months + 1, pv = loan)

    cat("Initial capital: ", loan, "\n")
    cat("Months: ", months, "\n")
    cat("Payment: ", payment, "\n")

    totalShouldPay &lt;- payment * months
    totalPaid &lt;- 0

    for(currentMonth in 1:months) {
        interest &lt;- currentCapital * monthlyRate
        repaid &lt;- payment - interest
        currentCapital &lt;- currentCapital - repaid

        overPayments &lt;- subset(over, over$month == currentMonth)
        if (length(overPayments) &gt; 0 &amp;&amp; nrow(overPayments) &gt; 0) {
            overPayments &lt;- sum(overPayments$payment)
            currentCapital &lt;- currentCapital - overPayments
            payment &lt;- -pmt(monthlyRate, nper = months + 1 - currentMonth, pv = currentCapital)
        }

        capital &lt;- append(capital, currentCapital)

        totalPaid &lt;- totalPaid + payment
        payments &lt;- append(payments, payment)
    }
    cat("Would have paid: ", round(totalShouldPay, 2), "\n")
    cat("Will pay: ", round(totalPaid, 2), "\n")
    cat("Saved: ", round(totalShouldPay - totalPaid, 2), "\n")
    return(data.frame(capital=capital, payments=payments))
}

overPayments &lt;- data.frame(
    month   = c(20,    25,    30,    35,    40), 
    payment = c(20000, 20000, 20000, 20000, 20000))

cap &lt;- mortgage(
    over = overPayments
)

#print(cap)
par(mfcol=c(1, 2))
plot(cap$payments, type="s", main = "Payments", xlab = "Month", ylab = "Payment")
plot(cap$capital, type="l", main = "Capital", xlab = "Month", ylab = "Remaining loan")
I spent clearly too much time on this... Main ideas:


your understanding of how the payment on a fixed mortgage is computed was wrong. The payment is computed once at the beginning and remains the same regardless of prepayments, which is why people who choose to prepay end up repaying their whole mortgage before the scheduled term, as the example below should show.
I added pmt as an argument to the function as it is best practice for a function to not use any variable defined outside its scope (the dreaded global variables)
A big no-no in your code was the use of constructs like capital &lt;- append(capital, currentCapital). At each iteration, a new and longer vector is created. This is slow and uses a lot of memory. Granted, you would need a very long mortgage to see the negative effects but it's good to learn to implement this the right way. You could a) pre-allocate a vector of length term.in.months and replace its value like this: capital[month.idx] &lt;- currentCapital. Or b) use a list: lists use pointers in memory so they don't suffer the issue I was describing as they grow in size. My implementation uses this b) approach where I grow a list named db. At the end, I am turning this list of monthly data into a data.frame.
You'll see I use things like 12L instead of 12. That's the difference between integers and numerics. It is recommended to use integers when possible as it can prevent (rare) issues regarding floating point errors. It uses less memory and can sometimes make your code faster. Again, you won't notice it here, but it is a good practice. 
Regarding @janos' comment about trying to avoid for loops. I agree, R works best and faster when vectorization can replace loops. However, your particular algorithm is a case of an iterative (state i+1 depends on state i) process so it cannot be vectorized. Whereas vectorization can replace loops only in processes where each iteration can be computed independently. So you will find that my answer still has a loop, in the form of a while().
I modified the variables' names to be closer to the official language. (I work in finance.)




mortgage &lt;- function(property.value = 1e6,
                     downpayment = 0.10,
                     interest.rate = 0.04,
                     term = 25L,
                     prepayments = NULL,
                     pmt.fun = pmt) {

   original.balance &lt;- property.value * (1 - downpayment)
   monthly.rate     &lt;- interest.rate / 12L
   term.in.months   &lt;- term * 12L
   monthly.payment  &lt;- -pmt.fun(monthly.rate, nper = term.in.months,
                                              pv = original.balance) 
   db &lt;- list()
   month.idx &lt;- 1L
   start.balance &lt;- original.balance

   while(start.balance &gt; 0) {

      balance.due       &lt;- start.balance * (1 + monthly.rate)
      payment.due       &lt;- min(monthly.payment, balance.due)
      prepayment        &lt;- if (is.null(prepayments)) 0 else
                           min(sum(subset(prepayments, month == month.idx)$payment),
                               balance.due - payment.due)
      total.payment     &lt;- payment.due + prepayment
      interest.payment  &lt;- start.balance * monthly.rate
      end.balance       &lt;- balance.due - total.payment
      principal.payment &lt;- start.balance - end.balance

      db[[month.idx]] &lt;- c(month             = month.idx,
                           start.balance     = start.balance,
                           balance.due       = balance.due,
                           payment.due       = payment.due,
                           total.payment     = total.payment,
                           prepayment        = prepayment,
                           interest.payment  = interest.payment,
                           principal.payment = principal.payment,
                           end.balance       = end.balance)
      month.idx     &lt;- month.idx + 1L
      start.balance &lt;- end.balance
   }
   as.data.frame(do.call(rbind, db))
}

source("http://pastebin.com/raw.php?i=q7tyiEmM")  # for pmt()

overPayments &lt;- data.frame(
   month   = c(20,    25,    30,    35,    40), 
   payment = c(20000, 20000, 20000, 20000, 20000))

cap1 &lt;- mortgage()
cap2 &lt;- mortgage(prepayments = overPayments)

par(mfcol=c(1, 2))
plot(c(cap1$start.balance, 0), type="l",
     main = "Without Prepayments", xlab = "Month", ylab = "Balance")
plot(c(cap2$start.balance, 0), type="l",
     main = "With Prepayments",    xlab = "Month", ylab = "Balance")