haskell R 中函数调用参数值的样式模式匹配
haskell style pattern matching of parameter values for function calls in R
在R中,是否可以根据参数值进行函数模式匹配ala Haskell?
即如果参数 x 是 ='foo', 运行 函数的一个版本,如果 x 是 'bar', 运行 另一个版本?显然这可以在必要时使用 if 语句来完成,但我想知道是否有更多的 'functional' 方法。
例如,要自动进行这种函数选择(foo1 与 foo2)而不需要 ifelse 语句来进行条件处理:
foo1 <- function(a) {
paste0(a, 'foo1')
}
foo2 <- function(a) {
paste0('baz', a, 'foo2')
}
x <- 'barp'
value <- ifelse(x == 'barp', foo1(x), foo2(x))
这可以根据对象的 "class" 来完成,但不是值。我对 Haskell 不是很熟悉,但我虽然 Haskell 也在 class/type 上调度而不是实际值?这是 R 实现:
> foo <- function(a) UseMethod("foo")
> foo.1 <- function(a) paste(a, 'foo1')
> foo.2 <- function(a) paste('baz', a, 'foo2')
>
> obj_1 <- structure("hello world", class="1")
> obj_2 <- structure("hello world", class="2")
>
> foo(obj_1)
[1] "hello world foo1"
> foo(obj_2)
[1] "baz hello world foo2"
这只会根据第一个参数的 class 进行分派。如果您想基于多个参数进行分派,可以使用 S4 方法。
对于一般代数数据类型,您可以定义自己的匹配函数助手。这些有时被称为 "eliminators",实质上是将您的 ADT 值转换成它们的 Church 编码。
例如,让我们翻译这个 Haskell 代码片段:
x = Just 3
y = Nothing
a = case x of Nothing -> 42 ; Just w -> w+100
b = case y of Nothing -> 42 ; Just w -> w+100
结果是:
# eliminator
matchMaybe <- function(x,kn,kj) {
ifelse(x[[1]]=='Nothing', kn(), kj(x[[2]]))
}
# tests
x <- list('Just', 3)
y <- list('Nothing')
a <- matchMaybe(x
,function() { 42 }
,function(w){ w+100 })
b <- matchMaybe(y
,function() { 42 }
,function(w){ w+100 })
但是请注意,深度 模式匹配很难以这种方式翻译。
也就是说,在 Haskell 中你可以做类似
的事情
case x of Just 10 -> 22 ; Nothing -> 42 ; Just w -> w+100
其中您同时匹配 Just
构造函数和内部 10
。这不能以方便的方式编码。
对于字符串,如 OP 示例中所示,可能的消除器可能是:
match <- function(x,v,kt,ke) {
ifelse(x==v, kt(),ke(x))
}
r <- match('foo'
, 'bar', function() { "then" }
, function(x) { "else" })
另外请记住,我对 R 语言不是很流利,因此可能有更好的方法。
在R中,是否可以根据参数值进行函数模式匹配ala Haskell?
即如果参数 x 是 ='foo', 运行 函数的一个版本,如果 x 是 'bar', 运行 另一个版本?显然这可以在必要时使用 if 语句来完成,但我想知道是否有更多的 'functional' 方法。
例如,要自动进行这种函数选择(foo1 与 foo2)而不需要 ifelse 语句来进行条件处理:
foo1 <- function(a) {
paste0(a, 'foo1')
}
foo2 <- function(a) {
paste0('baz', a, 'foo2')
}
x <- 'barp'
value <- ifelse(x == 'barp', foo1(x), foo2(x))
这可以根据对象的 "class" 来完成,但不是值。我对 Haskell 不是很熟悉,但我虽然 Haskell 也在 class/type 上调度而不是实际值?这是 R 实现:
> foo <- function(a) UseMethod("foo")
> foo.1 <- function(a) paste(a, 'foo1')
> foo.2 <- function(a) paste('baz', a, 'foo2')
>
> obj_1 <- structure("hello world", class="1")
> obj_2 <- structure("hello world", class="2")
>
> foo(obj_1)
[1] "hello world foo1"
> foo(obj_2)
[1] "baz hello world foo2"
这只会根据第一个参数的 class 进行分派。如果您想基于多个参数进行分派,可以使用 S4 方法。
对于一般代数数据类型,您可以定义自己的匹配函数助手。这些有时被称为 "eliminators",实质上是将您的 ADT 值转换成它们的 Church 编码。
例如,让我们翻译这个 Haskell 代码片段:
x = Just 3
y = Nothing
a = case x of Nothing -> 42 ; Just w -> w+100
b = case y of Nothing -> 42 ; Just w -> w+100
结果是:
# eliminator
matchMaybe <- function(x,kn,kj) {
ifelse(x[[1]]=='Nothing', kn(), kj(x[[2]]))
}
# tests
x <- list('Just', 3)
y <- list('Nothing')
a <- matchMaybe(x
,function() { 42 }
,function(w){ w+100 })
b <- matchMaybe(y
,function() { 42 }
,function(w){ w+100 })
但是请注意,深度 模式匹配很难以这种方式翻译。 也就是说,在 Haskell 中你可以做类似
的事情case x of Just 10 -> 22 ; Nothing -> 42 ; Just w -> w+100
其中您同时匹配 Just
构造函数和内部 10
。这不能以方便的方式编码。
对于字符串,如 OP 示例中所示,可能的消除器可能是:
match <- function(x,v,kt,ke) {
ifelse(x==v, kt(),ke(x))
}
r <- match('foo'
, 'bar', function() { "then" }
, function(x) { "else" })
另外请记住,我对 R 语言不是很流利,因此可能有更好的方法。