Skip to content

Instantly share code, notes, and snippets.

@bryangoodrich
Last active July 28, 2020 13:19
Show Gist options
  • Save bryangoodrich/8275787 to your computer and use it in GitHub Desktop.
Save bryangoodrich/8275787 to your computer and use it in GitHub Desktop.
List Out Of Lambda [in R] An adaptation of Steve Losh's JavaScript exploration[1] with a hat tip to Hadley Wickham's Advanced R Programming[2] that led me there. References [1] http://stevelosh.com/blog/2013/03/list-out-of-lambda/ [2] http://adv-r.had.co.nz/
# Created by Bryan Goodrich
# Version 0.1
#
# Title: List Out Of Lambda [in R]
#
# An adaptation of Steve Losh's JavaScript exploration[1] with a hat tip to
# Hadley Wickham's Advanced R Programming[2] that led me there.
#
# References
# [1] http://stevelosh.com/blog/2013/03/list-out-of-lambda/
# [2] http://adv-r.had.co.nz/
# ===============
# Basic Constructs
# ===============
empty_list <- NULL # Always starts a list; think of it as a "constant NULL function."
Prepend <- function (Element, List) {
function (x) if (x == "head") return (Element) else return (List)
}
Head <- function (List) return (List("head")) # By def of Prepend, will return the Element
# stored in the function environment (closure).
Tail <- function (List) return (List("tail")) # Can be anything other than "head" here.
IsEmpty <- function (List) return (is.null(List))
# Examples
# ["Alice", "Bobby", "Charlie"]
ppl <- Prepend("Alice", Prepend("Bobby", Prepend("Charlie", empty_list)))
IsEmpty(empty_list) # TRUE
IsEmpty(ppl) # FALSE
Head(ppl) # Alice
Tail(ppl) # Some function representing ["Bobby", "Charlie"]
Head(Tail(ppl)) # Bobby
Head(Tail(Tail(ppl))) # Charlie
# ===============
# Extended Functionality: Map
# ===============
.Map <- function (FUN, List) {
if (IsEmpty(List)) {
return (empty_list)
} else {
return (Prepend(FUN(Head(List)), .Map(FUN, Tail(List))))
}
}
# Examples
# [2, 5, 7]
num <- Prepend(2, Prepend(5, Prepend(7, empty_list)))
sqnum <- .Map(function(x) x*x, num)
Head(sqnum) # 4
Head(Tail(sqnum)) # 25
Head(Tail(Tail(sqnum))) # 49
# ===============
# Extended Functionality: Filter
# ===============
.Filter <- function (FUN, List) {
if (IsEmpty(List)) {
return (empty_list)
} else if (FUN(Head(List))) {
return (Prepend(Head(List), .Filter(FUN, Tail(List))))
} else {
return (.Filter(FUN, Tail(List)))
}
}
# Examples
oddnum <- .Filter(function(x) x%%2 == 1, num)
evenum <- .Filter(function(x) x%%2 == 0, num)
Head(oddnum); Head(Tail(oddnum)) # [5, 7]
Head(evenum) # [2]
# ===============
# Extended Functionality: Logicals
# ===============
NOT <- function (x) if (x) FALSE else TRUE
OR <- function (a, b) if (a) TRUE else {if (b) TRUE else FALSE}
AND <- function (a, b) NOT(OR(NOT(a), NOT(b))) # a&b == !(!a v !b)
# Examples: Truth Tables
cbind("P" = c(T, T, F, F),
"Q" = c(T, F, T, F),
"~Q" = c(NOT(T), NOT(F), NOT(T), NOT(F)),
"PvQ" = c(OR(T,T), OR(T,F), OR(F, T), OR(F,F)),
"P^Q" = c(AND(T,T), AND(T,F), AND(F,T), AND(F,F)))
# ===============
# New Construction: Remove equality checking and 'if' language feature
# ===============
Prepend <- function (Element, List) {
function (selector) selector(Element, List)
}
Head <- function (List) List(function(head, tail) return (head))
Tail <- function (List) List(function(head, tail) return (tail))
# Examples
# ["First", "Second", "Third"]
positions <- Prepend("First", Prepend("Second", Prepend("Third", empty_list)))
Head(positions) # First
Head(Tail(positions) # Second
Head(Tail(Tail(positions))) # Third
# ===============
# New Construction: Improve new types and make empty_list functional
# - Depends on language features: functions, TRUE, FALSE
# - Uses NULL in arguments to empty_list, but can use anything as it is ignored.
# ===============
empty_list <- function (selector) selector(NULL, NULL, TRUE)
Prepend <- function (Element, List) {
function (selector) selector(Element, List, FALSE)
}
Head <- function (List) List(function(head, tail, empty) return (head))
Tail <- function (List) List(function(head, tail, empty) return (tail))
IsEmpty <- function (List) List(function(head, tail, eol) return (eol))
# Examples
# [0, 1, 3]
num <- Prepend(0, Prepend(1, Prepend(3, empty_list)))
sqnum <- .Map(function(x) x*x, num)
Head(sqnum) # 0
Head(Tail(sqnum)) # 1
Head(Tail(Tail(sqnum))) # 9
oddnum <- .Filter(function(x) x%%2 == 1, num)
evenum <- .Filter(function(x) x%%2 == 0, num)
Head(oddnum); Head(Tail(oddnum)) # [1, 3]
Head(evenum) # [0]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment