FunctionalPerl

 view release on metacpan or  search on metacpan

docs/design.md  view on Meta::CPAN

Check the [functional-perl website](http://functional-perl.org/) for
properly formatted versions of these documents.

---

# The design principles used in the functional-perl library

<with_toc>

## General

### Be properly functional first.

As already mentioned in the introduction on the [[howto]] page, the
modules are built using the functional paradigm from the ground up (as
much as makes sense; e.g. iterations in simple functions are often
written as loops instead of tail
recursion<small><sup>1</sup></small>). A sequences API to build
alternative implementations (like iterator based, or optimizing away
intermediate results) might be added in the future.

<small><sup>1</sup> But this is mainly done just because it's
(currently) faster, and since currently Perl does not offer
first-class continuations.  Avoiding loop syntax and using function
calls everwhere makes it possible to suspend and resume execution
arbitrarily in a language like Scheme, without mutation getting in the
way; but this doesn't apply to current Perl 5.</small>

### Try to limit dependencies if sensible.

E.g. avoiding the use of `Sub::Call::Tail`, `Method::Signatures`,
`MooseX::MultiMethods` or `autobox` in the core modules. (Some tests,
[examples](../examples/README.md) and [Htmlgen](../htmlgen/README.md)
use them.) Declaring dependencies in `FunctionalPerl::Dependencies` so
that tests can skip modules with such dependencies.

### Generally provide functionality both as functions and methods.

*NOTE: since this was written, the method call based style has become
 the primary way to provide functionality, and function based access
 is spotty now. TODO: rewrite this section. BTW, providing functions
 would be good but provide generic wrappers (which also work for
 builtin types which can't have methods)--TODO.*

The sequence processing functions use the argument order conventions
from functional programming languages (Scheme, Ocaml, Haskell). The
methods move the sequence argument to the object position.

For example, both

    list_map *inc, list (1,3,4)

and

    list (1,3,4)->map (\&inc)

result in the same choice of algorithm. The shorter method name is
possible thanks to the dispatch on the type of the object. Compare to:

    stream_map *inc, array_to_stream ([1,3,4])

or the corresponding

    array_to_stream ([1,3,4])->map (\&inc)

which shows that there's no need to specify the kind of sequence
when using method syntax.

This actually needed an implementation trick: streams are just
lazily computed linked lists, hence the object on which the `map`
method is being called is just a generic promise. The promise could
return anything upon evaluation, not just a list pair. Thus it can't
be known what `map` implementation to call without evaluating the
promise. After evaluation, it's just a pair, though, at which point
it can't be known whether to call the `list_map` or `stream_map`
implementation. So how it works is that promises have a catch-all
(AUTOLOAD), which forces evaluation, and then looks for a method
with a `stream_` prefix first (which will find the `stream_map`
method in this example). If that fails, it will call the original
method name on the forced value.

So the way to make it work both for lazily and eagerly computed pairs
is to put both a `map` and a `stream_map` method into the
`FP::List::List` namespace (which is the parent class of
`FP::List::Pair` and `FP::List::Null`). When the pair was provided
lazily, the above implementation will dispatch to `stream_map`, which
normally makes sense since the user will want a lazy result from a
lazy input.

Note that this dispatch mechanism is only run for the first pair of
the list; afterwards, the code stays in either `list_map` or
`stream_map`(*). This means that prepending a value to a stream makes
the non-lazy map implementation be used:

    cons (0, array_to_stream [1,3,4])->map (\&inc)

returns an eagerly evaluated list, not a stream. If that's not
what you want, you can still prefix the method name with `stream_`
yourself to force the lazy variant:

    cons (0, array_to_stream [1,3,4])->stream_map (\&inc)

returns a stream.

(*) Question: should the dispatch really happen for each cell? Then
the eager part of a mixed list/stream would still be mapped eagerly,
and the lazy part lazily. (TODO: measure the overhead.)

NOTE: providing both functions and methods makes things more
complicated. The reason it was done so far is rather accidental, as
originally only functions were provided. Some functions like `car` and
`cons` are now wrappers that actually do method calls if they
can. `cons` still needs to remain a function because it doesn't
necessarily receive an object as its rest argument. TODO: figure out
whether to continue providing functions, perhaps reduce the offer to
those strictly needed and otherwise request the user to build them on
the fly using `the_method`? Or figure out a way to generate them for
whole packages easily. The second reason other than the need to use
`the_method` is that the functions can take arguments in the same
order as traditional functional programming languages (the object does
not need to come first, and with multiple objects it can be unclear
which to use as the one to dispatch on).

Idea: use `Class::Multimethods` or `Class::Multimethods::Pure` or
`MooseX::MultiMethods` to provide multimethods as alternative to
methods; this would allow to retain the traditional argument positions
and still use short names. (Perhaps look at Clojure as an example?)

### Use of `*foo` vs `\&foo`

Both of these work for passing a subroutine as a value, with the
following differences:

The code reference (`\&foo`):

 - is the same type of data as what the expression `sub { .. }`
   returns, and hence what's most often teached.

 - clearly only ever represents a subroutine, whereas `*foo` is
   ambiguous and can point to any type: the named package entries for
   subroutines, IO handles, scalars, arrays, hashes, plus any other
   kind of object by way of scalars.

 - serialization to bytes is problematic (can only be done using
   complex modules and only for a limited range of Perl code, and
   includes serializing the whole code of the subroutine)

 - can be used as a value in lexical variables as arguments to goto
   even without using a `&` prefix, as in `my $f = \&foo; goto $f`

The glob (`*foo`):

 - looks arguably visually cleaner, and may be easier to type

 - later redefinitions to the subroutine it points to are being
   reflected (as it points to the subroutine indirectly by name)

 - can be serialized easily (as it's just a *name*)

 - nicer for debugging when not using `show` from `FP::Show` or other
   ways using introspection, as one can directly see the subroutine
   package and name, not just an anonymous code ref,

 - this code fails: `my $f = *foo; goto $f`. But this still works:
   `my $f = *foo; goto &$f`. (`Sub::Call::Tail`'s `tail` is fine.)

 - there are no builtin perl checks for the wrong type, i.e. passing
   `*foo` where an array reference is expected will silently access
   the `@foo` package variable, even if it was never declared (empty
   in this case), while passing `\&foo` would have the interpreter
   point out the error.

Quick benchmarking of subroutine calls of the two variants did not
detect a performance difference.

`FP::Predicate`'s `is_procedure` accepts globs if they contain a value
in the CODE slot, i.e. it adapts its meaning to "*can* represent a
subroutine". (But Todo: should it return true for any other callable
(overloaded object) as well? (How can the latter be implemented, by
way of checking for a '(&' method?))

Earlier versions of FunctionalPerl suggested to use globs. Due to
globs being a usually rarely used feature in Perl, and the possibility
for its mutation on a distance, it does not recommend it any longer,
and all code and examples have been changed to use `\&` instead.



( run in 1.765 second using v1.01-cache-2.11-cpan-e86d8f7595a )