Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   Code Gallery (https://forums.graalonline.com/forums/forumdisplay.php?f=179)
-   -   Prelude (https://forums.graalonline.com/forums/showthread.php?t=134261142)

WhiteDragon 11-23-2010 03:35 AM

Prelude
 
Here is a pack of useful functions that let you operate on arrays and integers

PHP Code:

//#CLIENTSIDE

function onCreated() {

  
/* MISCELLANEOUS FUNCTIONS */

  // Return whatever is passed in
  
this.id = function (temp.a) {
    return 
temp.a;
  };
  
  
// Return the first parameter and ignore the second.
  
this.const = function (temp.atemp.b) {
    return 
temp.a;
  };

  
// Combine two functions and return a new function which executes them in order.
  // i.e.,    compose(f, g)(x) = f(g(x))
  
this.compose = function (temp.f1temp.f2) {
    
temp.= function (temp.x) {
      
temp.f1 this.(@"freevars_"@temp).f1;
      
temp.f2 this.(@"freevars_"@temp).f2;
      return (@
temp.f1)((@temp.f2)(temp.x));
    };
    
this.(@"freevars_"@temp.f).f1 temp.f1;
    
this.(@"freevars_"@temp.f).f2 temp.f2;
    return 
temp.f;
  };
    
  
//  Flip the parameters of a function.
  //  flip(f)(x, y) = f(y,x)
  
this.flip = function (temp.f1) {
    
temp.= function (temp.atemp.b) {
      
temp.f1 this.(@"freevars_"@temp.f).f1;
      return (@
temp.f1)(temp.btemp.a);
    };
    
this.(@"freevars_"@temp.f).f1 temp.f1;

    return 
temp.f;
  };
  
  
// Until p(x) is true, x = f(x) every recursive step. Return the final x (after all the fs are applied).
  
this.until = function (temp.ptemp.ftemp.x) {
    if ((@
temp.p)(temp.x)) {
      return 
temp.x;
    } else {
      return (@
temp)(temp.ptemp.f, (@temp.f)(temp.p));
    }
  };

  
/* BOOLEAN OPERATIONS */

  // Just negates a boolean. Useful for composing.
  
this.not = function (temp.a) {
    return !
temp.a;
  };


  
/* NUMERIC OPERATIONS */

  // Negates a number.
  
this.negate = function (temp.a) {
    return -
temp.a;
  };

  
// Get the sign of a number.
  
this.signum = function (temp.a) {
    if (
temp.0) {
      return -
1;
    } else if (
temp.== 0) {
      return 
0;
    } else {
      return 
1;
    }
  };

  
// Return the remainder of an integer division.
  
this.rem = function(temp.atemp.n) {
    return 
temp.temp.n*int(temp.a/temp.n);
  };

  
// Subtract two numbers.
  
this.subtract = function (temp.atemp.b) {
    return 
temp.temp.a;
  };

  
// Checks if a number is even
  
this.even = function (temp.a) {
    
temp.temp.a/2;
    return 
int(temp.a) != temp.a;
  };

  
// Checks if a number is odd
  
this.odd this.compose(this.notthis.even);

  
// Returns the greatest positive integer that divides both x and y.
  
this.gcd = function (temp.xtemp.y) {
    
temp.gcd2 = function (temp.atemp.b) {
      if (
temp.== 0) {
        return 
temp.a;
      } else {
        return (@
temp)(temp.bthis.rem(temp.atemp.b));
      }
    };
    if (
temp.== && temp.== 0) {
      
// error
    
} else {
      return (@
temp.gcd2)(abs(temp.x), abs(temp.y));
    }
  };
  
  
// Returns the smallest integer that both x and y divide.
  
this.lcm = function (temp.xtemp.y) {
    if (
temp.== || temp.== 0) {
      return 
0;
    } else {
      return 
abs((temp./ (this.gcd(temp.xtemp.y))) * temp.y);
    }
  };
  

  
  
/* LIST OPERATIONS */

  // Take a function and a list. Return a new list that has that function applied across it.
  
this.map = function (temp.ftemp.a) {
    
temp.temp.a.size();
  
    
temp.= {};
    for (
temp.0temp.temp.stemp.i++) {
      
temp.b.insert(temp.i, (@temp.f)(temp.a[temp.i]));
    }
  
    return 
temp.b;
  };

  
// Take a function and a list. Return a list that only has elements where temp.f was True for them.
  
this.filter = function (temp.ftemp.a) {
    
temp.temp.a.size();

    
temp.= {};  
    for (
temp.0temp.temp.stemp.i++) {
      if ((@
temp.f)(temp.a[temp.i]) == true) {
        
temp.b.add(temp.a[temp.i]);
      }
    }
  
    return 
temp.b;
  };

  
// return the first element in a list.
  
this.head = function (temp.a) {
    return 
temp.a[0];
  };
  
  
// return the last element of the list.
  
this.last = function (temp.a) {
    return 
temp.a[temp.a.size()-1];
  };
  
  
// return everything but the first element in a list.
  
this.tail = function (temp.a) {
    return 
temp.a.subarray(1);
  };
  
  
// return everything but the last element in a list.
  
this.init = function (temp.a) {
    return 
temp.a.subarray(0temp.a.size()-2);
  };
  
  
// takes a list and returns a new list that in reverse.
  
this.reverse = function (temp.a) {
    
temp.aSize temp.a.size();
    
temp.= new [temp.aSize];
    for (
temp.0temp.temp.aSizetemp.i++) {
      
temp.b[temp.i] = temp.a[temp.aSize-1-temp.i];
    }
    return 
temp.b;
  };

  
// Takes a 2-parameter function, a value, and a list of values, and combines the array into a new value based on that function moving from the left to the right. 
  
this.foldl = function (temp.ftemp.inittemp.a) {
    
temp.temp.a.size();

    
temp.result temp.init;
  
    for (
temp.0temp.temp.stemp.i++) {
      
temp.result = (@temp.f)(temp.resulttemp.a[temp.i]);
    }
  
    return 
temp.result;
  };

  
// Same as foldl, but no default value (the list must not be empty in this case). 
  
this.foldl1 = function (temp.ftemp.a) {
    
temp.temp.a.size();

    
temp.result temp.a[0];
  
    for (
temp.1temp.temp.stemp.i++) {
      
temp.result = (@temp.f)(temp.resulttemp.a[temp.i]);
    }

    return 
temp.result;  
  };

  
// Same as foldl but starts from the right of the list and moves left.
  
this.foldr = function (temp.ftemp.inittemp.a) {
    
temp.temp.a.size();

    
temp.result temp.init;
  
    for (
temp.temp.s-1temp.>= 0temp.i--) {
      
temp.result = (@temp.f)(temp.a[temp.i], temp.result);
    }
  
    return 
temp.result;
  };

  
// same as foldr but with no default value (list must be non-empty).
  
this.foldr1 = function (temp.ftemp.a) {
    
temp.temp.a.size();

    
temp.result temp.a[temp.s-1];
  
    for (
temp.temp.s-2temp.>= 0temp.i--) {
      
temp.result = (@temp.f)(temp.a[temp.i], temp.result);
    }

    return 
temp.result;  
  };



  
/* sublists */
  
  // takes the first temp.num values from a list
  
this.takee = function (temp.numtemp.a) {
    return 
temp.a.subarray(0temp.num);
  };
  
  
// drops the first temp.num values from a list
  
this.drop = function (temp.numtemp.a) {
    return 
temp.a.subarray(temp.num);
  };
  
  
// splits a list into two parts at temp.num
  
this.splitAt = function (temp.numtemp.a) {
    return {
temp.a.subarray(0temp.num), temp.a.subarray(temp.num)};
  };
  
  
// keep taking elements from temp.xs until temp.p is false on that element.
  
this.takeWhile = function (temp.ptemp.xs) {
    
temp.xsSize temp.xs.size();
    
temp.= {};
    for (
temp.0temp.temp.xsSizetemp.i++) {
      if ((@
temp.p)(temp.xs[temp.i])) {
        
temp.n.add(temp.xs[temp.i]);
      } else {
        break;
      }
    }
    return 
temp.n;
  };

  
// keep dropping elements from temp.xs while temp.p is true on that element.
  
this.dropWhile = function (temp.ptemp.xs) {
    
temp.xsSize temp.xs.size();
    
temp.= {};
    for (
temp.0temp.temp.xsSizetemp.i++) {
      if (!(@
temp.p)(temp.xs[temp.i])) {
        break;
      }
    }
    for (
temp.temp.itemp.temp.xsSizetemp.x++) {
      
temp.n.add(temp.xs[temp.x]);
    }
    return 
temp.n;
  };

  
// splits an array into two based on the function temp.p. This is basically {takeWhile(p,xs), dropWhile(p,xs)}
  
this.span = function (temp.ptemp.xs) {
    
temp.xsSize temp.xs.size();
    
temp.= {};
    for (
temp.0temp.temp.xsSizetemp.i++) {
      if ((@
temp.p)(temp.xs[temp.i])) {
        
temp.n.add(temp.xs[temp.i]);
      } else {
        break;
      }
    }
    
temp.n2 = {};
    for (
temp.temp.itemp.temp.xsSizetemp.x++) {
      
temp.n2.add(temp.xs[temp.x]);
    }
    return {
temp.ntemp.n2};
  };
  
  
// span, but with a negated temp.p
  
this.break = function (temp.ptemp.xs) {
    return 
this.span(this.compose(this.nottemp.p), temp.xs);
  };


Put this in a class, e.g., prelude, then:
PHP Code:

temp.= new TStaticVar();
temp.p.join("prelude");

temp.= function (temp.x) { return temp.x*2; }
echo(
temp.p.map(temp.f, {1,2,3,4})); // returns {2,4,6,8} 

Inspired by the Haskell Prelude. Also note there is some more documentation/examples at that link for the functions I provided. (Also more functions that I haven't converted to GS yet.)

DrakilorP2P 11-23-2010 09:47 PM

I've been wondering; do you use these abstract scripts in real projects or is it just for curiosity?

WhiteDragon 11-23-2010 09:52 PM

Quote:

Originally Posted by DrakilorP2P (Post 1613010)
I've been wondering; do you use these abstract scripts in real projects or is it just for curiosity?

Depends. If it's a project that only I will be touching then I use this stuff, but otherwise I try to keep it simple for anyone else who might need to work on it. Can't expect everyone to be interested enough to go learn a whole set of functions just to understand a small script.

adam 12-18-2010 01:29 AM

:d

Codein 12-18-2010 02:04 AM

It's funny how I come across this post straight after checking out Haskell's website on the front page of HN.

These functions look really fun to play with. Not really seen an equivalent of map, reduce and filter in GScript before.

12171217 12-18-2010 03:10 AM

Is it faster to use the modulus operator to check if it's even or odd? That's what I've always done.

fowlplay4 12-18-2010 07:34 AM

Quote:

Originally Posted by 12171217 (Post 1616559)
Is it faster to use the modulus operator to check if it's even or odd? That's what I've always done.

PHP Code:

function onCreated() {
  for (
temp.0temp.5temp.i++) {
    
temp.init timevar2;
    
testEven();
    
temp.sum += timevar2 temp.init;
  }
  echo(
temp.sum 5);
}

function 
testEven() {
  for (
temp.0temp.200000temp.i++) {
    
isEven(temp.i);
  }
}

function 
isEven(x) {
  return 
int(2) == (2);
}

function 
isEvenMod(x) {
  return (
2) == 0;


isEvenMod Averaged: 0.281881904
isEven Averaged: 0.300032424

Using modulus is slightly faster (0.01~ seconds in most cases) but I wouldn't consider it something that would become a bottleneck, well in GS2 anyway.

salesman 12-18-2010 07:04 PM

Quote:

Originally Posted by fowlplay4 (Post 1616587)
PHP Code:

function isEven(x) { // missing divide operation
  
return int(x) == (2);
}
function 
isEven(x) {
  return 
int(2) == (2);



You're missing an operation in the isEven() function!

The way I usually look at it, checking if its even by int(x / 2) == (x / 2) requires four basic operations (int, 2 divides, and a comparison), at least two references (x twice, maybe a third for the int() function call). Modulus requires two basic operations (mod, and a comparison) and only one variable reference.

But yeah I agree, the difference is so small it probably wouldn't matter in most cases.

fowlplay4 12-18-2010 08:19 PM

So I ran it again with the right isEven script and it was pretty much the same result.

Cloven 12-18-2010 10:34 PM

Quote:

Originally Posted by salesman (Post 1616649)
You're missing an operation in the isEven() function!

The way I usually look at it, checking if its even by int(x / 2) == (x / 2) requires four basic operations (int, 2 divides, and a comparison), at least two references (x twice, maybe a third for the int() function call). Modulus requires two basic operations (mod, and a comparison) and only one variable reference.

But yeah I agree, the difference is so small it probably wouldn't matter in most cases.

As a wise man once told me: "This isn't NASA." It's kind of ironic how often such a stupid sounding saying like that applies.
:D

Codein 01-04-2011 01:53 AM

But wait...

PHP Code:

function isEven(value)
{
  return !(
value 1);




All times are GMT +2. The time now is 08:49 PM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.