Forcing specific data types as arguments to a function

前端 未结 3 1297
傲寒
傲寒 2020-12-31 13:01

I was just wondering if there was a way to force a function to only accept certain data types, without having to check for it within the function; or, is this not possible b

3条回答
  •  半阙折子戏
    2020-12-31 13:20

    You could write a wrapper like the following:

    check.types = function(classes, func) {
        n = as.name
    
        params = formals(func)
        param.names = lapply(names(params), n)
    
        handler = function() { }
        formals(handler) = params
    
        checks = lapply(seq_along(param.names), function(I) {
            as.call(list(n('assert.class'), param.names[[I]], classes[[I]]))
        })
        body(handler) = as.call(c(
            list(n('{')),
            checks,
            list(as.call(list(n('<-'), n('.func'), func))),
            list(as.call(c(list(n('.func')), lapply(param.names, as.name))))
        ))
    
        handler
    }
    
    assert.class = function(x, cls) {
        stopifnot(cls %in% class(x))
    }
    

    And use it like

    f = check.types(c('numeric', 'numeric'), function(x, y) {
        x + y
    })
    
    > f(1, 2)
    [1] 3
    
    > f("1", "2")
    Error: cls %in% class(x) is not TRUE
    

    Made somewhat inconvenient by R not having decorators. This is kind of hacky and it suffers from some serious problems:

    1. You lose lazy evaluation, because you must evaluate an argument to determine its type.

    2. You still can't check the types until call time; real static type checking lets you check the types even of a call that never actually happens.

    Since R uses lazy evaluation, (2) might make type checking not very useful, because the call might not actually occur until very late, or never.

    The answer to (2) would be to add static type information. You could probably do this by transforming expressions, but I don't think you want to go there.

提交回复
热议问题