function.anubis 7.74 KB


read list.anubis




   *** (5) Function facilities.

      *** (5.1) A generic 'identity' function.

public define $T
   identity
     (
       $T x
     ) =
   x. 
   
   
      *** (5.2) Writing 'x.f' instead of 'f(x)'.

   The next definition enables to write 'x.f' instead of 'f(x)' for applying a function to
   its argument (works for functions of 1 argument).  In particular, if 'f' is an implicit
   destructor (which  has always 1 argument) of  some type, this makes  the application of
   this  destructor look  like  the C  syntax 'x.f'  for  extracting a  component from  an
   agglomeration (analogous to a field from a structure).
      
   The binary operator  '.' has been introduced 2006/11/09 in  version 1.7.10. Because the
   fact that paragraphs must end by a dot (necessarily followed by either a white space, a
   line feed, a carriage return or a tabulator), this binary operator needs its right hand
   operand  glued onto  it.   So 'x. f'  will  not  be  correct, because  the  dot may  be
   understood as an end of paragraph.
   
   
public define inline $U
   $T x .$T -> $U f
     =
   f(x). 
   
      *** (5.3) A generic 'force' function 
   
   Allows to simplify some code writing where it isn't necessary to test the result of a 
   Maybe(...) and a default value is suffisent.
   
public define inline $T
  force
  (
    Maybe($T)  mb,
    $T        default
  ) =
  if mb is
  {
    failure         then default,
    success(value)   then value
  }.

// deprecated old name     
public define inline $T
  force_Type
  (
    Maybe($T)  mb,
    $T         default
  ) =
  if mb is
  {
    failure         then default,
    success(value)   then value
  }.
   
      *** (5.4) The Kleisli applicator (simulating exceptions). 
   
   It is often the case that instead of having a function of type 'T -> U' and an argument
   of  type 'T',  we have  a function  of type  'T ->  Maybe(U)' and  an argument  of type
   'Maybe(T)'. In this case,  applying 'f' to 'a' still makes sens,  and this sens is what
   we need  in practice. Now, since the  usual applicative syntaxe is  not overloadable in
   Anubis 1, we use the dot syntax as in the previous section. 
   
public define inline Maybe($U)
   Maybe($T) a .$T -> Maybe($U) f
     =
   if a is 
     {
       failure      then failure, 
       success(a1)  then f(a1)
     }.
   
   The same one for the type schema 'Result':
   
public define inline Result($E,$U)
   Result($E,$T) a .$T -> Result($E,$U) f
     =
   if a is 
     {
       error(e)   then error(e), 
       ok(a1)     then f(a1)
     }.
   
   The effect of the  above two definitions may be seen as  a simultation of the mechanism
   'exceptions' (which do not exist in Anubis).
   
   

      *** (4.8) Mapping functions
   
   The most basic 'map' function is defined in 'predefined.anubis' (section 'Mapping a function ...').
   
         *** (4.8.0) 'map' for 'Maybe'. 
         
public define Maybe($U)
   map
     (
       $T -> $U    f, 
       Maybe($T)   a         
     ) =
   if a is 
   {
     failure     then failure, 
     success(b)  then success(f(b))
   }.


         *** (4.8.1) 'map' for non empty lists. 
   
   'map_forget' is the same as 'map', except that it forgets the result. It is better to use
   map_forget(f,l) than forget(map(f,l)), because in the first case the result not constructed
   at all. 

public define One
   map_forget
     (
       $A -> $B f, 
       List($A) l
     ) =
   if l is
     {
       [ ] then unique, 
       [h . t] then 
         forget(f(h)); map_forget(f,t)
     }.
     
   
         *** (4.8.3) 'map' with a parameter:

public define List($C)
  map
    (
      ($A,$B) -> $C   f, 
      $A              p,
      List($B)        l
    ) =
  if l is 
    {
      [ ] then [ ],
      [h . t] then 
        with x = f(p,h), 
        [x . map(f,p,t)]
    }. 

   
   
         *** (4.8.4) 'map and append'
   
define List($T) map_append($A -> List($T) f, List($A) l, List($T) acc) = if l is
  {
    [ ]     then acc,
    [h . t] then map_append(f, t, append(acc,f(h)))
  }.

public define List($T) map_append($A -> List($T) f, List($A) l) = map_append(f, l, [ ]).

  public define List($T)
   map_append
     (
       $A -> List($T)  f,
       List($A)        l
     ) =
   if l is 
     {
       []       then [],
       [h . t]  then append(f(h),map_append(f,t))
     }.

   
   
         *** (4.8.5) 'map and select'. 
   
public define List($B)
   map_select
     (
       $A -> Maybe($B)    f,    // Only those who don't give 'failure' are kept.
       List($A)           l
     ) =
   if l is 
     {
       [ ] then [ ], 
       [h . t] then 
         if f(h) is 
           {
             failure      then map_select(f,t),
             success(x)   then [x . map_select(f,t)]
           }
     }.
   
   
   
         *** (4.8.6) 'map and iterate'.
   
   Given that n1 = init, n2= next(n1), n3 = next(n2), ...
   the list [a1, a2, a3,...] is transformed into [f(n1,a1),f(n2,a2),f(n3,a3),...]. 

public define List($B)
   map_iterate
     (
       ($T,$A) -> $B      f, 
       List($A)           l,
       $T                 init,
       $T -> $T           next
     ) =
   if l is
     {
       [ ] then [ ], 
       [h . t] then 
         with x = f(init,h), 
         [x . map_iterate(f,t,next(init),next)]
     }. 
   
   A variant where 'next' can know about the element just treated
   
public define List($B)
   map_iterate
     (
       ($T,$A) -> $B      f, 
       List($A)           l,
       $T                 init,
       ($T,$A) -> $T      next
     ) =
   if l is
     {
       [ ] then [ ], 
       [h . t] then 
         with x = f(init,h), 
         [x . map_iterate(f,t,next(init,h),next)]
     }. 
   
      
   
   
         *** (4.8.7) 'map select and iterate'. 
   
   A combination of the previous two. 
   
public define List($B)
   map_select_iterate
     (
       ($T,$A) -> Maybe($B)      f, 
       List($A)                  l,
       $T                        init,
       $T -> $T                  next
     ) =
   if l is
     {
       [ ] then [ ], 
       [h . t] then 
         if f(init,h) is 
           {
             failure     then 
               map_select_iterate(f,t,init,next),
             success(x)  then 
               [x . map_select_iterate(f,t,next(init),next)]
           }
     }. 
   
   
         *** (4.8.8) 'map and escape'. 
   
   'map_escape' applies a function f of type $A -> Maybe($B)$ to all the elements of a list. If 
   one of the results is 'failure' the final result is 'failure'. The final result is success(<some list>)
   if and only if all the applications of f yield success(<something>). 

public define Maybe(List($B)) 
   map_escape
     (
       $A -> Maybe($B)          f,
       List($A)                 l
     ) =
   if l is
     {
       [ ] then success([ ]),               // nothing to perform
       [h . t] then if f(h) is              // perform the first one
         {
           failure     then failure,     
           success(r)  then if map_escape(f,t) is    // convert all the others
             {
               failure          then failure, 
               success(others)  then success([r . others])
             }
         }
     }.


      *** (4.8.9) Map in parallel and wait or don't wait for completion. 
      
   Apply in parallel the function f to all elements of a list
   and wait or not for completion of all processes.

public type Wait: 
   wait, 
   dont_wait. 

public define One map_delegate
  (
    $T -> One         f, 
    List($T)          l,
    Wait              w
  ) =
  if w is 
  {
    wait then 
      with v = var((Int)length(l)),
      map_forget(($T t) |-> (delegate f(t); protect v <- *v-1, unique), l);
      checking every 1 millisecond, wait for *v = 0 then unique,
    dont_wait then 
      map_forget(($T t) |-> (delegate f(t), unique), l)
  }.