Last active
July 28, 2020 13:19
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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