Sign in to follow this  
bexphones

functional programming a challenge for you and a learning for me !

Recommended Posts

hi, i'm happy to play now with short code and modularize them together.

What saves time and readability !

But in this case i don't see what it's possible to do with the function foreach.

Is it possible to use foreach like this config with a trick in the hide_weapon_internal ?

 


//normal function  who works 
if(dalle_moving[0]){
     for (var j = 0; j < dalle_moving.length; j++){
	dalle_moving[j].hide()
     }
}

////////////////////////////////////////////////////////////////////////////////////
//NOW WITH FUNCTIONAL PROGRAMATION

function is_exist(obj){
	if(typeof obj != "undefined"){
		return true; 
	}else{
		return false; 
	}
}

function foreach(table,action){
	for(var i=0;i<table.length;i++){
		action(table[i]);
	}
}

//////////////////////////////////////////
var hide_enemy=function(obj){
    is_exist(obj[0]) && foreach(obj,obj.hide)
}
hide_enemy(dalle_moving)
//////////////////////////////////////////

//obj.hide don't works because i must say action(obj[i].hide()) 
//is there a trick to do that with the function foreach as she is ?


i have the feeling that 's possible ....no?

Share this post


Link to post
Share on other sites

Couple of quick pointers:

 

1) Avoid using function names that closely match reserved words or already existing native code. 

Array.prototype.forEach

already exists, so avoid names like 'forEach'

 

2) is_exist sounds weird, and can be simplified:

const is_defined = (obj) => obj !== undefined

just keep in mind that there are better check than this, and consider cases like when obj is null, etc (be careful when doing comparisons and read on the topic)

 

3) you are trying to use a method that can be accessed by each individual item in an array. If it is always hide, you can simply do

const hide_enemies = (enemies) => enemies.forEach( (enemy) => enemy.hide() );

or if you need to call other methods, just use a string to represent a possible method name

const hide_enemies = (enemies, actionString) => enemies.forEach( (enemy) => enemy[actionString]() );

In old-school syntax, you could write

function hide_enemies(enemies){
  enemies.forEach( function(enemy){

    return enemy.hide();
  });
}

If you tell me more about why you are checking is_exist(obj[0]), we could probably avoid awkward checks.

 

Finally, you could check out this quick guide to Array functions that may provide you with more information.

Edited by ldd
added a link to provide more information

Share this post


Link to post
Share on other sites

hi,

thanks very much for these explanations.

your quick guide for array is easy to understand , thanks again ;)

9 hours ago, ldd said:

If you tell me more about why you are checking is_exist(obj[0]), we could probably avoid awkward checks.

i use an array to stock my objects.

var enemy={}

next i create the enemy  i need for each levels with a prototype and methods.

enemy[0]=new _proto_enemy()

each level have different number of enemies. level 1 have for example 2 enemies and level2 > 4, etc....

i check if enemy exist in an update method to each levels to apply method on hem like collisions with another object (player), add in the game(game.add.existing(enemy[0]), debug hem.

finally to loop trough and apply also method but with other object or methods.

Share this post


Link to post
Share on other sites
//WHY THIS NOT WORKS ?
function hide_enemies(obj,action){
	obj.forEach(function(item){
		return item.action()
	})
}

//WHY THIS WORKS ?
function hide_enemies(obj){
	obj.forEach(function(item){
		return item.hide()
	})
}

hi again :rolleyes: could you explain  why it doesn't work for the example 1 ? how must i declare "action" ? if i run hide_enemies(dalle,hide) it return the error item.action is not a function. for obj exist you have true, it's not necessary to invoke him, hide_enemies() works without because we make foreach. Thanks.

PS : i'm not yet ready for this :

const hide_enemies = (enemies, actionString) => enemies.forEach( (enemy) => enemy[actionString]() );

because i need to console.log sometimes what went wrong and in this case it's difficult.

Share this post


Link to post
Share on other sites
On 11/08/2017 at 1:29 AM, ldd said:

1) Avoid using function names that closely match reserved words or already existing native code. 

Why? There's no problem with this. Extending built-in prototypes is generally frowned upon with good arguments to back it up still, but `forEach` is not a reserved word, its just an instance member on a built-in, of which there are hundreds. If I built an event emitter should I not call one of its methods `addEventListener`? 

On 11/08/2017 at 1:29 AM, ldd said:

3) you are trying to use a method that can be accessed by each individual item in an array. If it is always hide, you can simply do


const hide_enemies = (enemies) => enemies.forEach( (enemy) => enemy.hide() );

I think the whole point of bex creating a custom for each function is for performance. (for reference, I'd do it exactly the same and just use [].forEach, at least at first).

28 minutes ago, bexphones said:

 


//WHY THIS NOT WORKS ?
function hide_enemies(obj,action){
	obj.forEach(function(item){
		return item.action()
	})
}

//WHY THIS WORKS ?
function hide_enemies(obj){
	obj.forEach(function(item){
		return item.hide()
	})
}

 

There are a couple of ways of invoking a method of an instance:

var speaker = {
  prefix: '::',
  say: function (message) {
    console.log(this.prefix, message)
  }
}

// Using dot notation to access the method
speaker.say('hello!')
// $ :: hello!

// Using square brackets and strings
speaker['say']('world!')
// $ :: world!

In your examples you're using the dot notation to invoke a function, in your first example you're trying to invoke `action` of `item` (item.action()), which probably doesn't exist.

If you want to invoke a dynamic method of an object then using the square brackets notation would work:

function callForAllEnemies (obj, method) {
  obj.forEach(function (item) {
    return item['methods]()
  })
}

I've renamed it as it is now a generic helper to call a method for all enemies, if you explicitly call the function hide_enemies then you may as well explicitly call item.hide().

Note that your custom foreach function can do this as well with some small changes:

function foreach (list, action) {
  let i = list.length
  while (--i) {
    list[i][action]()
  }
}

(As I'm assuming this function is for perf I've also used a negative counting while list, which I think is still generally the fastest array iteration method)

You can swap things around and go more generic with things too if you wanted to get in to refactoring a little:

const all = method => list => {
  let i = list.length
  while (--i) {
    list[i][action]()
  }
}

const hideAll = all('hide')
const showAll = all('show')

hideAll(enemies)

All sorts of ways to solve problems.

Share this post


Link to post
Share on other sites
9 minutes ago, mattstyles said:

You can swap things around and go more generic with things too if you wanted to get in to refactoring a little:


const all = method => list => {
  let i = list.length
  while (--i) {
    list[i][action]()
  }
}

const hideAll = all('hide')
const showAll = all('show')

hideAll(enemies)

i start with lua langage +

after i learn javascript ++

and now définitively i love FP +++

Share this post


Link to post
Share on other sites

maybe yet a question

how do you do to perform that  ?


function foreach(tableau,action){
	for(var i=0;i<tableau.length;i++){
		action(tableau[i]);
	}
}


const actions = console.log(this.name) && console.log(this.number)
foreach(dalle,actions)

and this also ?
 

function test_args(arg1,arg2){

console.log(arg1)

console.log(arg2)

}

test_args("koala","cat") //koala, cat

test args("koala") //return only koala without errors

 

Share this post


Link to post
Share on other sites

You want to specify multiple actions to your function?

There are quite a few ways to achieve this, the simplest is just to ensure that `actions` is an array and just iterate over that array of functions calling them, but, you could go a different route with variadic arguments:

function run (...args) {
  const data = args.shift()
  let i = data.length
  while (--i >= 0) {
    args.forEach(fn => fn(data[i]))
  }
}

const arr = [1, 2, 3]
run(arr, i => console.log(i))
// 3 9 2 4 1 1

Something like this should do what you want, although there are a few ways to skin this cat, see the MDN resource on function arguments.

Note that this uses the spread syntax, you can achieve the same with `Array.from(arguments)`, which is detailed on the mdn resource.

All this does is grab the dataset from your list of arguments and then iterate over every other arguments calling it, you could do the same simply by insisting your actions parameter is an array.

Share this post


Link to post
Share on other sites

Yeah, fn isn't reserved, list of reserved words here, you could also use `func` but, rather than the generic word `function` we should probably be a bit more explicit by naming this function by what it does, in this case, maybe `iterator` would be more suitable and more useful for the next developer (or future self) to be able to quickly understand what the code does.

Note that arrow functions can have an implicit return if you don't create an explicit function body, so, for example:

const map = fn => list => list.map(fn)
const square = i => i * i
const squareList = map(square)

const arr = [1, 2, 3]
squareList(arr)
// 1, 4, 9

There is so much going on here, and the reuse it fantastic.

`square` could be rewritten as:

function square (num) {
  return num * num
}

but arrows functions make this more succinct and even though we haven't explicitly used the `return` syntax we are in fact returning the square of the argument given to the function.

Similarly we do the same thing for `map` where we return the output of `list.map(fn)` and pass the function `fn` to each entry in the list.

This sort of pattern is fantastic for reuse as to create functionality that doubles numbers in a list we can simply add a doubling function and then create a new function which can map that over an array:

const double = i => i * 2
const doubleList = map(double)

doubleList(arr)
// 2, 4, 6

We could have implemented doubling and squaring with just 2 functions, but, those functions would not be minimal, each would have to implement the number operation (doubling or squaring) AND implement the mapping algorithm (in this case just calling array.map, but, you can imagine as we move away from trivial examples this could get more complex). By extracting the mapping functionality our `double` and `square` functions deal with just one job, they are then consumed by a function that handles mapping.

This has so many benefits:

* As each function is minimal and deals with a single concern it is far far easier to test these functions and test them comprehensively.

* We test just one thing, with the naive solutions we'd also be implicitly testing our map functionality, which is sub-optimal, we want to test that stuff explicitly and thoroughly.

* If we change how we iterate over a list later (for example, maybe our lists get implemented as linked-lists or as objects, where array.map is no longer viable), we ONLY change our `map` function, everything else stays the same. This is golden, but as we've already written comprehensive tests for these functions we know that our changes don't break our library/framework/application.

* We can name functions more easily as they do just one thing. Important for debugging and more important for any developers wanting to reuse our code (including our future selves when we come back to this stuff x months from now and have forgotten what we did back then!).

Share this post


Link to post
Share on other sites

since i have print Professor Frisby's, i 'm reading it and it's very interesting thanks. Still a question...it's interesting becausew with fp i must re-learn the basic;

this function return effectively false :

var debub_position=true

              is_clic_valid =(count,f) =>{
		let condition = (count) => {
			switch(count){
				case 0:
					return true
				case 1:
					return true
				case 2:
					return true
				default:
					return false
			}
		}

		if ( condition == true && f == true ){
			return true
		}else{
			return false
		}
	}

	let ex=is_clic_valid(4,debug_position)
	console.log(ex) // return false

But in this case it's true because i change this line however i think it's correct...

		(condition && f )? true : false
var debub_position=true

              is_clic_valid =(count,f) =>{
		let condition = (count) => {
			switch(count){
				case 0:
					return true
					//break
				case 1:
					return true
					//break
				case 2:
					return true
					//break
				default:
					return false
					//break
			}
		}
		( condition && f ) ? true : false
	}

	let ex=is_clic_valid(4,debug_position)
	console.log(ex) // return true

what 's my mistake ? think also that break is not necessary in this case ? no ?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.