Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,3 +1,4 @@
---
category:
- Functions and subroutines
- Simple

View file

@ -0,0 +1,28 @@
# A function without arguments: #
f();
# or #
f;
# A function with a fixed number of arguments: #
f(1, x);
# ALGOL 68 does not support optional arguments, variable numbers of arguments, or named
arguments.
However, some functions may take an argument "0" as an instruction to use the default value
(sort of a pseudo-optional argument). #
# In "Talk:Call a function" a statement context is explained as
"The function is used as an instruction (with a void context),
rather than used within an expression." Based on that,
both ALGOL examples above are already in a statement context.
For full ALGOL compatibility, though, they should be in the form "VOID (f ());" #
# A function's return value being used: #
x := f(y);
# There is no distinction between built-in functions and user-defined functions. #
# A subroutine is simply a function that returns VOID. #
# If the function is declared with argument(s) of mode REF MODE,
then those arguments are being passed by reference. #

View file

@ -0,0 +1,103 @@
import std.traits;
enum isSubroutine(alias F) = is(ReturnType!F == void);
void main() {
void foo1() {}
// Calling a function that requires no arguments:
foo1();
foo1; // Alternative syntax.
void foo2(int x, int y) {}
immutable lambda = function int(int x) => x ^^ 2;
// Calling a function with a fixed number of arguments:
foo2(1, 2);
foo2(1, 2);
cast(void)lambda(1);
void foo3(int x, int y=2) {}
// Calling a function with optional arguments:
foo3(1);
foo3(1, 3);
int sum(int[] arr...) {
int tot = 0;
foreach (immutable x; arr)
tot += x;
return tot;
}
real sum2(Args...)(Args arr) {
typeof(return) tot = 0;
foreach (immutable x; arr)
tot += x;
return tot;
}
// Calling a function with a variable number of arguments:
assert(sum(1, 2, 3) == 6);
assert(sum(1, 2, 3, 4) == 10);
assert(sum2(1, 2.5, 3.5) == 7);
// Calling a function with named arguments:
// Various struct or tuple-based tricks can be used for this,
// but currently D doesn't have named arguments.
// Using a function in statement context (?):
if (1)
foo1;
// Using a function in first-class context within an expression:
assert(sum(1) == 1);
auto foo4() { return 1; }
// Obtaining the return value of a function:
immutable x = foo4;
// Distinguishing built-in functions and user-defined functions:
// There are no built-in functions, beside the operators, and
// pseudo-functions like assert().
int myFynction(int x) { return x; }
void mySubroutine(int x) {}
// Distinguishing subroutines and functions:
// (A subroutine is merely a function that has no explicit
// return statement and will return void).
pragma(msg, isSubroutine!mySubroutine); // Prints: true
pragma(msg, isSubroutine!myFynction); // Prints: false
void foo5(int a, in int b, ref int c, out int d, lazy int e, scope int f) {}
// Stating whether arguments are passed by value, by reference, etc:
alias STC = ParameterStorageClass;
alias psct = ParameterStorageClassTuple!foo5;
static assert(psct.length == 6); // Six parameters.
static assert(psct[0] == STC.none);
static assert(psct[1] == STC.none);
static assert(psct[2] == STC.ref_);
static assert(psct[3] == STC.out_);
static assert(psct[4] == STC.lazy_);
static assert(psct[5] == STC.scope_);
// There are also inout and auto ref.
int foo6(int a, int b) { return a + b; }
// Is partial application possible and how:
import std.functional;
alias foo6b = partial!(foo6, 5);
assert(foo6b(6) == 11);
}

View file

@ -0,0 +1,25 @@
a-function \ requiring no arguments
a-function \ with a fixed number of arguents
a-function \ having optional arguments
a-function \ having a variable number of arguments
a-function \ having such named arguments as we have in Forth
' a-function var ! \ using a function in a first-class context (here: storing it in a variable)
a-function \ in which we obtain a function's return value
\ forth lacks 'statement contenxt'
\ forth doesn't distinguish between built-in and user-defined functions
\ forth doesn't distinguish between functions and subroutines
\ forth doesn't care about by-value or by-reference
\ partial application is achieved by creating functions and manipulating stacks
: curried 0 a-function ;
: only-want-third-argument 1 2 rot a-function ;
\ Realistic example:
: move ( delta-x delta-y -- )
y +! x +! ;
: down ( n -- ) 0 swap move ;
: up ( n -- ) negate down ;
: right ( n -- ) 0 move ;
: left ( n -- ) negate right ;

View file

@ -0,0 +1,70 @@
program main
implicit none
integer :: a
integer :: f, g
logical :: lresult
interface
integer function h(a,b,c)
integer :: a, b
integer, optional :: c
end function
end interface
write(*,*) 'no arguments: ', f()
write(*,*) '-----------------'
write(*,*) 'fixed arguments: ', g(5,8,lresult)
write(*,*) '-----------------'
write(*,*) 'optional arguments: ', h(5,8), h(5,8,4)
write(*,*) '-----------------'
write(*,*) 'function with variable arguments: Does not apply!'
write(*,*) 'An option is to pass arrays of variable lengths.'
write(*,*) '-----------------'
write(*,*) 'named arguments: ', h(c=4,b=8,a=5)
write(*,*) '-----------------'
write(*,*) 'function in statement context: Does not apply!'
write(*,*) '-----------------'
write(*,*) 'Fortran passes memorty location of variables as arguments.'
write(*,*) 'So an argument can hold the return value.'
write(*,*) 'function result: ', g(5,8,lresult) , ' function successful? ', lresult
write(*,*) '-----------------'
write(*,*) 'Distinguish between built-in and user-defined functions: Does not apply!'
write(*,*) '-----------------'
write(*,*) 'Calling a subroutine: '
a = 30
call sub(a)
write(*,*) 'Function call: ', f()
write(*,*) '-----------------'
write(*,*) 'All variables are passed as pointers.'
write(*,*) 'Problems can arise if instead of sub(a), one uses sub(10).'
write(*,*) '-----------------'
end program
!no argument
integer function f()
f = 10
end function
!fixed number of arguments
integer function g(a, b, lresult)
integer :: a, b
logical :: lresult
g = a+b
lresult = .TRUE.
end function
!optional arguments
integer function h(a, b, c)
integer :: a, b
integer, optional :: c
h = a+b
if(present(c)) then
h = h+10*c
end if
end function
!subroutine
subroutine sub(a)
integer :: a
a = a*100
write(*,*) 'Output of subroutine: ', a
end subroutine

View file

@ -0,0 +1,11 @@
import (
"image"
"image/gif"
"io/ioutil"
"strings"
"unicode"
)
func f() (int, float64) { return 0, 0 }
func g(int, float64) int { return 0 }
func h(string, ...int) {}

View file

@ -0,0 +1,9 @@
f()
g(1, 2.0)
// If f() is defined to return exactly the number and type of
// arguments that g() accepts than they can be used in place:
g(f())
// But only without other arguments, this won't compile:
//h("fail", f())
// But this will:
g(g(1, 2.0), 3.0)

View file

@ -0,0 +1,8 @@
h("ex1")
h("ex2", 1, 2)
h("ex3", 1, 2, 3, 4)
// such functions can also be called by expanding a slice:
list := []int{1,2,3,4}
h("ex4", list...)
// but again, not mixed with other arguments, this won't compile:
//h("fail", 2, list...)

View file

@ -0,0 +1 @@
gif.Encode(ioutil.Discard, image.Black, &gif.Options{NumColors: 16})

View file

@ -0,0 +1 @@
if 2*g(1, 3.0)+4 > 0 {}

View file

@ -0,0 +1,9 @@
fn := func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
return r
}
strings.Map(fn, "Spaces removed")
strings.Map(unicode.ToLower, "Test")
strings.Map(func(r rune) rune { return r + 1 }, "shift")

View file

@ -0,0 +1,4 @@
a, b := f() // multivalue return
_, c := f() // only some of a multivalue return
d := g(a, c) // single return value
e, i := g(d, b), g(d, 2) // multiple assignment

View file

@ -0,0 +1,2 @@
list = append(list, a, d, e, i)
i = len(list)

View file

@ -0,0 +1 @@
f()

View file

@ -0,0 +1 @@
f(1,sin(x), g -> int(g(t),t=0..1)

View file

@ -0,0 +1 @@
f(1, sin(x), g -> int(g(t),t=0..1)

View file

@ -0,0 +1 @@
f(1, sin(x), g -> int(g(t),t=0..1)

View file

@ -0,0 +1 @@
f(a,b,method = foo)

View file

@ -0,0 +1 @@
f(a); f(b);

View file

@ -0,0 +1 @@
f(a) + g(b)

View file

@ -0,0 +1 @@
x := f(1)

View file

@ -0,0 +1,2 @@
> type( op, 'builtin' );
true

View file

@ -0,0 +1,4 @@
foo(); # Call foo on the null list
&foo(); # Ditto
foo($arg1, $arg2); # Call foo on $arg1 and $arg2
&foo($arg1, $arg2); # Ditto; ignores prototypes

View file

@ -0,0 +1 @@
foo;

View file

@ -0,0 +1 @@
&foo;

View file

@ -0,0 +1 @@
goto &foo;

View file

@ -0,0 +1,3 @@
&$fooref('foo', 'bar');
&{$fooref}('foo', 'bar');
$fooref->('foo', 'bar');

View file

@ -8,6 +8,13 @@ def fixed_args(x, y):
# call
fixed_args(1, 2) # x=1, y=2
## Can also called them using the parameter names, in either order:
fixed_args(y=2, x=1)
## Can also "apply" fixed_args() to a sequence:
myargs=(1,2) # tuple
fixed_args(*myargs)
def opt_args(x=1):
print(x)
# calls
@ -41,6 +48,18 @@ def is_builtin(x):
is_builtin(pow) # True
is_builtin(is_builtin) # False
# Very liberal function definition
def takes_anything(*args, **kwargs):
for each in args:
print(each)
for key, value in sorted(kwargs.items()):
print("%s:%s" % (key, value))
# Passing those to another, wrapped, function:
wrapped_fn(*args, **kwargs)
# (Function being wrapped can have any parameter list
# ... that doesn't have to match this prototype)
## A subroutine is merely a function that has no explicit
## return statement and will return None.

View file

@ -0,0 +1,58 @@
### Calling a function that requires no arguments
no_args <- function() NULL
no_args()
### Calling a function with a fixed number of arguments
fixed_args <- function(x, y) print(paste("x=", x, ", y=", y, sep=""))
fixed_args(1, 2) # x=1, y=2
fixed_args(y=2, x=1) # y=1, x=2
### Calling a function with optional arguments
opt_args <- function(x=1) x
opt_args() # x=1
opt_args(3.141) # x=3.141
### Calling a function with a variable number of arguments
var_args <- function(...) print(list(...))
var_args(1, 2, 3)
var_args(1, c(2,3))
var_args()
### Calling a function with named arguments
fixed_args(y=2, x=1) # x=1, y=2
### Using a function in statement context
if (TRUE) no_args()
### Using a function in first-class context within an expression
print(no_args)
### Obtaining the return value of a function
return_something <- function() 1
x <- return_something()
x
### Distinguishing built-in functions and user-defined functions
# Not easily possible. See
# http://cran.r-project.org/doc/manuals/R-ints.html#g_t_002eInternal-vs-_002ePrimitive
# for details.
### Distinguishing subroutines and functions
# No such distinction.
### Stating whether arguments are passed by value or by reference
# Pass by value.
### Is partial application possible and how
# Yes, see http://rosettacode.org/wiki/Partial_function_application#R

View file

@ -0,0 +1,65 @@
def ??? = throw new NotImplementedError // placeholder for implementation of hypothetical methods
def myFunction0() = ???
myFunction0() // function invoked with empty parameter list
myFunction0 // function invoked with empty parameter list omitted
def myFunction = ???
myFunction // function invoked with no arguments or empty arg list
/* myFunction() */ // error: does not take parameters
def myFunction1(x: String) = ???
myFunction1("foobar") // function invoked with single argument
myFunction1 { "foobar" } // function invoked with single argument provided by a block
// (a block of code within {}'s' evaluates to the result of its last expression)
def myFunction2(first: Int, second: String) = ???
val b = "foobar"
myFunction2(6, b) // function with two arguments
def multipleArgLists(first: Int)(second: Int, third: String) = ???
multipleArgLists(42)(17, "foobar") // function with three arguments in two argument lists
def myOptionalParam(required: Int, optional: Int = 42) = ???
myOptionalParam(1) // function with optional param
myOptionalParam(1, 2) // function with optional param provided
def allParamsOptional(firstOpt: Int = 42, secondOpt: String = "foobar") = ???
allParamsOptional() // function with all optional args
/* allParamsOptional */ // error: missing arguments for method allParamsOptional;
// follow with `_' if you want to treat it as a partially applied function
def sum[Int](values: Int*) = values.foldLeft(0)((a, b) => a + b)
sum(1, 2, 3) // function accepting variable arguments as literal
val values = List(1, 2, 3)
sum(values: _*) // function acception variable arguments from collection
sum() // function accepting empty variable arguments
def mult(firstValue: Int, otherValues: Int*) = otherValues.foldLeft(firstValue)((a, b) => a * b)
mult(1, 2, 3) // function with non-empty variable arguments
myOptionalParam(required = 1) // function called with named arguments (all functions have named arguments)
myFunction2(second = "foo", first = 1) // function with re-ordered named arguments
mult(firstValue = 1, otherValues = 2, 3) // function with named variable argument as literal
val otherValues = Seq(2, 3)
mult(1, otherValues = otherValues: _*) // function with named variable argument from collection
val result = myFunction0() // function called in an expression context
myFunction0() // function called in statement context
/* myOptionalParam(optional = 1, 2) */ // error: positional after named argument.
def transform[In, Out](initial: In)(transformation: In => Out) = transformation(initial)
val result = transform(42)(x => x * x) // function in first-class context within an expression
def divide(top: Double, bottom: Double) = top / bottom
val div = (divide _) // partial application -- defer application of entire arg list
val halve = divide(_: Double, 2) // partial application -- defer application of some arguments
class Foo(var value: Int)
def incFoo(foo: Foo) = foo.value += 1 // function showing AnyRef's are passed by reference
/* def incInt(i: Int) = i += 1 */ // error: += is not a member of Int
// (All arguments are passed by reference, but reassignment
// or setter must be defined on a type or a field
// (respectively) in order to modify its value.)
// No distinction between built-in functions and user-defined functions
// No distinction between subroutines and functions

View file

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<demo>
<!--
XSLT 1.0 actually defines two function-like constructs that
are used variously depending on the context.
-->
<xsl:call-template name="xpath-function-demos"/>
<xsl:call-template name="xslt-template-demos"/>
</demo>
</xsl:template>
<xsl:template name="xpath-function-demos">
<!--
A 'function' in XSLT 1.0 is a function that can be called from
an XPath 1.0 expression (such as from "select" or "test"
attribute of several XSLT elements). The following demos apply
to these functions.
-->
<!-- Calling function that requires no arguments -->
<!-- false() always returns a boolean false value -->
<line>This test is <xsl:if test="false()">NOT</xsl:if> OK.</line>
<!-- Calling a function with a fixed number of arguments -->
<!-- not() takes exactly 1 argument. starts-with() takes exactly 2 arguments. -->
<line>'haystack' does <xsl:if test="not(starts-with('haystack', 'hay'))">NOT</xsl:if> start with 'hay'.</line>
<!-- Calling a function with optional arguments -->
<!-- If the third argument of substring() is omitted, the length of the string is assumed. -->
<line>'<xsl:value-of select="substring('haystack', 1, 3)"/>' = 'hay'</line>
<line>'<xsl:value-of select="substring('haystack', 4)"/>' = 'stack'</line>
<!-- Calling a function with a variable number of arguments -->
<!-- concat() accepts two or more arguments. -->
<line>'<xsl:value-of select="concat('abcd', 'efgh')"/>' = 'abcdefgh'</line>
<line>'<xsl:value-of select="concat('ij', 'kl', 'mn', 'op')"/>' = 'ijklmnop'</line>
<!--
Aggregate functions such as sum() and count() accept nodesets.
This isn't quite the same as varargs but are probably worth
mentioning.
-->
<line>The number of root elements in the input document is <xsl:value-of select="count(/*)"/> (should be 1).</line>
<!-- Calling a function with named arguments -->
<!-- XPath 1.0 uses only positional parameters. -->
<!-- Using a function in statement context -->
<!--
In general, XPath 1.0 functions have no side effects, so calling
them as statements is useless. While implementations often allow
writing extensions in imperative languages, the semantics of
calling a function with side effects are, at the very least,
implementation-dependent.
-->
<!-- Using a function in first-class context within an expression -->
<!-- Functions are not natively first-class values in XPath 1.0. -->
<!-- Obtaining the return value of a function -->
<!--
The return value of the function is handled as specified by the
various contexts in which an XPath expression is used. The
return value can be stored in a "variable" (no destructive
assignment is allowed), passed as a parameter to a function or a
template, used as a conditional in an <xsl:if/> or <xsl:when/>,
interpolated into text using <xsl:value-of/> or into an
attribute value using brace syntax, and so forth.
-->
<!-- Here, concat() is interpolated into an attribute value using braces ({}). -->
<line foo="{concat('Hello, ', 'Hello, ', 'Hello')}!">See attribute.</line>
<!-- Distinguishing built-in functions and user-defined functions -->
<!--
Given that functions aren't first-class here, the origin of any
given function is known before run time. Incidentally, functions
defined by the standard are generally unprefixed while
implementation-specific extensions (and user extensions, if
available) must be defined within a separate namespace and
prefixed.
-->
<!-- Distinguishing subroutines and functions -->
<!--
There are no "subroutines" in this sense—everything that looks
like a subroutine has some sort of return or result value.
-->
<!-- Stating whether arguments are passed by value or by reference -->
<!-- There is no meaningful distinction since there is no mechanism by which to mutate values. -->
<!-- Is partial application possible and how -->
<!-- Not natively. -->
</xsl:template>
<xsl:template name="xslt-template-demos">
<!--
A 'template' in XSLT 1.0 is a subroutine-like construct. When
given a name (and, optionally, parameters), it can be called
from within another template using the <xsl:call-template/>
element. (An unnamed template is instead called according to its
match and mode attributes.) The following demos apply to named
templates.
-->
<!--
Unlike with functions, there are no built-in named templates to
speak of. The ones used here are defined later in this
transform.
-->
<!--
Answers for these prompts are the same as with XPath functions (above):
Using a function in statement context
Distinguishing subroutines and functions
Stating whether arguments are passed by value or by reference
Is partial application possible and how
-->
<!-- Calling function that requires no arguments -->
<xsl:call-template name="nullary-demo"/>
<!--
Note that even if a template has no parameters, it has access to
the current node (.) as of the time of the call. This
<xsl:apply-templates/> runs a matching template above that calls
the template "nullary-context-demo" with no parameters. Another
way to manipulate a template's idea of which node is current is
by calling from inside a <xsl:for-each/> loop.
-->
<xsl:apply-templates select="/*" mode="nullary-context-demo-mode"/>
<!--
A template parameter is made optional in the definition of the
template by supplying an expression as its select attribute,
which is evaluated and used as its value if the parameter is
omitted. Note, though, that all template parameters have an
implicit default value, the empty string, if the select
attribute is not specified. Therefore, all template parameters
are always optional, even when semantically they should not be.
-->
<!-- Calling a function with a fixed number of arguments -->
<working note="When all parameters are supplied">
<xsl:call-template name="ternary-demo">
<xsl:with-param name="a" select="4"/>
<xsl:with-param name="b">3</xsl:with-param>
<xsl:with-param name="c" select="2 + 3"/>
</xsl:call-template>
</working>
<broken note="When the third parameter 'c' is omitted">
<xsl:call-template name="ternary-demo">
<xsl:with-param name="a" select="4"/>
<xsl:with-param name="b">3</xsl:with-param>
</xsl:call-template>
</broken>
<!-- Calling a function with optional arguments -->
<!-- With the optional third parameter -->
<working name="When all parameters are supplied">
<xsl:call-template name="binary-or-ternary-demo">
<xsl:with-param name="a" select="4"/>
<xsl:with-param name="b" select="3"/>
<xsl:with-param name="c" select="5"/>
</xsl:call-template>
</working>
<!-- Without the optional third parameter (which defaults to 0) -->
<working name="When 'a' and 'b' are supplied but 'c' is defaulted to 0">
<xsl:call-template name="binary-or-ternary-demo">
<xsl:with-param name="a" select="4"/>
<xsl:with-param name="b" select="3"/>
</xsl:call-template>
</working>
<!-- Calling a function with a variable number of arguments -->
<!--
Templates are not varargs-capable. Variable numbers of arguments
usually appear in the form of a nodeset which is then bound to a
single parameter name.
-->
<!-- Calling a function with named arguments -->
<!--
Other than what comes with the current context, template
arguments are always named and can be supplied in any order.
Templates do not support positional arguments. Additionally,
even arguments not specified by the template may be passed; they
are silently ignored.
-->
<!-- Using a function in first-class context within an expression -->
<!-- Templates are not first-class values in XSLT 1.0. -->
<!-- Obtaining the return value of a function -->
<!--
The output of a template is interpolated into the place of the
call. Often, this is directly into the output of the transform,
as with most of the above examples. However, it is also possible
to bind the output as a variable or parameter. This is useful
for using templates to compute parameters for other templates or
for XPath functions.
-->
<!-- Which is the least of 34, 78, 12, 56? -->
<xsl:variable name="lesser-demo-result">
<!-- The variable is bound to the output of this call -->
<xsl:call-template name="lesser-value">
<xsl:with-param name="a">
<!-- A call as a parameter to another call -->
<xsl:call-template name="lesser-value">
<xsl:with-param name="a" select="34"/>
<xsl:with-param name="b" select="78"/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="b">
<!-- and again -->
<xsl:call-template name="lesser-value">
<xsl:with-param name="a" select="12"/>
<xsl:with-param name="b" select="56"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<!-- The variable is used here in an XPath expression -->
<line>
<xsl:value-of select="concat('And the answer, which should be 12, is ', $lesser-demo-result, ', of course.')"/>
</line>
<!-- Distinguishing built-in functions and user-defined functions -->
<!-- Virtually all templates are user-defined. -->
</xsl:template>
<!-- Templates supporting template demos above -->
<xsl:template match="/*" mode="nullary-context-demo-mode">
<xsl:call-template name="nullary-context-demo"/>
</xsl:template>
<xsl:template name="nullary-demo">
<line>No parameters needed here!</line>
</xsl:template>
<xsl:template name="nullary-context-demo">
<!-- When a template is called it has access to the current node of the caller -->
<xsl:for-each select="self::*">
<line>The context element here is named "<xsl:value-of select="local-name()"/>"</line>
</xsl:for-each>
</xsl:template>
<xsl:template name="ternary-demo">
<!-- This demo requires, at least semantically, all three parameters. -->
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:param name="c"/>
<line>(<xsl:value-of select="$a"/> * <xsl:value-of select="$b"/>) + <xsl:value-of select="$c"/> = <xsl:value-of select="($a * $b) + $c"/></line>
</xsl:template>
<xsl:template name="binary-or-ternary-demo">
<!-- This demo requires the first two parameters, but defaults the third to 0 if it is not supplied. -->
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:param name="c" select="0"/>
<line>(<xsl:value-of select="$a"/> * <xsl:value-of select="$b"/>) + <xsl:value-of select="$c"/> = <xsl:value-of select="($a * $b) + $c"/></line>
</xsl:template>
<xsl:template name="lesser-value">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:choose>
<xsl:when test="number($a) &lt; number($b)">
<xsl:value-of select="$a"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$b"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>