How to remove mutability when creating an increasing value such as a position?









up vote
3
down vote

favorite












I am trying to use a more functional approach in my code, and I have a variable posx which represents a position on the X axis.



It changes over time xpos = xpos + pos:



const createCircle = (xpos, fill) => 
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)





How can I not mutate the variable xpos?



I've read that it is not good to mutate variables... so how would I do it then here?



Or is this ok in this case?



Rest of the code:



const circleOpts = 
xpos: 20,
fill: 0,


const createCircle = (xpos, fill) =>
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)




let bola;

function setup ()
createCanvas(300,500)
background(3)
bola = createCircle(circleOpts)


function draw ()
bola.move(10)










share|improve this question























  • You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
    – CertainPerformance
    Nov 10 at 23:13














up vote
3
down vote

favorite












I am trying to use a more functional approach in my code, and I have a variable posx which represents a position on the X axis.



It changes over time xpos = xpos + pos:



const createCircle = (xpos, fill) => 
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)





How can I not mutate the variable xpos?



I've read that it is not good to mutate variables... so how would I do it then here?



Or is this ok in this case?



Rest of the code:



const circleOpts = 
xpos: 20,
fill: 0,


const createCircle = (xpos, fill) =>
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)




let bola;

function setup ()
createCanvas(300,500)
background(3)
bola = createCircle(circleOpts)


function draw ()
bola.move(10)










share|improve this question























  • You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
    – CertainPerformance
    Nov 10 at 23:13












up vote
3
down vote

favorite









up vote
3
down vote

favorite











I am trying to use a more functional approach in my code, and I have a variable posx which represents a position on the X axis.



It changes over time xpos = xpos + pos:



const createCircle = (xpos, fill) => 
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)





How can I not mutate the variable xpos?



I've read that it is not good to mutate variables... so how would I do it then here?



Or is this ok in this case?



Rest of the code:



const circleOpts = 
xpos: 20,
fill: 0,


const createCircle = (xpos, fill) =>
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)




let bola;

function setup ()
createCanvas(300,500)
background(3)
bola = createCircle(circleOpts)


function draw ()
bola.move(10)










share|improve this question















I am trying to use a more functional approach in my code, and I have a variable posx which represents a position on the X axis.



It changes over time xpos = xpos + pos:



const createCircle = (xpos, fill) => 
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)





How can I not mutate the variable xpos?



I've read that it is not good to mutate variables... so how would I do it then here?



Or is this ok in this case?



Rest of the code:



const circleOpts = 
xpos: 20,
fill: 0,


const createCircle = (xpos, fill) =>
return
move: (pos) =>
xpos = xpos + pos
noStroke()
ellipse( xpos,10,10,10)




let bola;

function setup ()
createCanvas(300,500)
background(3)
bola = createCircle(circleOpts)


function draw ()
bola.move(10)







javascript functional-programming processing p5.js






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 11 at 0:51









Kevin Workman

32.9k53967




32.9k53967










asked Nov 10 at 23:11









Giorgio Martini

15318




15318











  • You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
    – CertainPerformance
    Nov 10 at 23:13
















  • You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
    – CertainPerformance
    Nov 10 at 23:13















You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
– CertainPerformance
Nov 10 at 23:13




You're not actually mutating there - you're only reassigning (it's a primitive, after all - primitives are immutable)
– CertainPerformance
Nov 10 at 23:13












2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted










It's absolutely fine in this case.



In your case, you're using a single variable to represent a single value. Since this value changes over time, it makes perfect sense that the variable would change over time.



Generally, I'd be very skeptical of claims that XYZ is always a good idea or always a bad idea. Everything depends on context.






share|improve this answer






















  • What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
    – user633183
    Nov 11 at 5:37










  • @user633183 Yes, all of that is absolutely fine in this context.
    – Kevin Workman
    Nov 11 at 6:23










  • @user633183 I'm not really sure what you mean? Flagging.
    – Kevin Workman
    Nov 11 at 7:14


















up vote
-1
down vote













This is a really broad question, but I'll give you my advice. Start looking at setup -



function setup () 
createCanvas(300,500) // where is the canvas created?

background(3) // background(3)? 3?
// does this set the background? on what?

bola = createCircle(circleOpts) // this is better
// createCircle accepts an input and it returns a value
// don't forget: const bola = ...




In general, you'll want to design functions that accept inputs and return outputs. Let's even think about the types of inputs and outputs they might have



createCircle : (x: Int, y: Int, r: Int) -> Element

moveCircle : (Element, x: Int, y: Int) -> Element

createCanvas : (h: Int, w: Int, bg: Int, elements: [Element]) -> Canvas

setBackground : (c: Canvas, bg: Int) -> Canvas

draw: (c: Canvas, e: Element) -> Canvas


Let's answer your question broadly here. We will implement createCircle which constructs a simple object. moveCircle will accept a Circle as input, but it will not mutate it -






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





We'll continue implementing more of your program. Each function has sensible parameters and produces an output



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas // <-- similar technique as moveCircle
( canvas.h // we create a new canvas using the canvas's height
, canvas.w // and the canvas's width
, bg // setting the new bg here
, canvas.elements // and keeping the existing canvas's elements
)

const draw = (canvas, element) =>
createCanvas // <-- same technique as above
( canvas.h // ...
, canvas.w // ...
, canvas.bg // same canvas bg this time
, append // append the new element to
( canvas.elements // the canvas's elements
, element
)
)

const append = (xs, x) =>
xs .concat ([ x ]) // <-- immutability everywhere (ie, no .push)


Lastly I'll introduce render. This is our side effect that takes a Canvas and renders it to the screen. A hallmark feature of side-effecting (impure) functions is that they have no return value (null, undefined, or void) -



render: (c: Canvas) -> Void

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)



This just "renders" the Canvas to the console, but the effect is the same. Write to stdout, a file, send it across the network, it doesn't matter; What matters is we kept everything pure up until this point.



Here's what a program might look like that uses our functions above -



const main = () =>
const canvas =
setBackground // set background
( createCanvas (300, 500) // on a 300x500 canvas
, 3 // to bg:3 (yellow?)
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle)) // <-- render is an efffect
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle)) // <-- effect
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2



You can verify the results in your own browser below






const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






I want to briefly revisit createCanvas and change it from -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )


to -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( Element: "canvas", h, w, bg, elements )


This would allow canvases to be composed of other canvases. Designing composable data types is a cornerstone of functional programming -



const canvas =
createCanvas
( 300
, 500
, 0
, [ shape1, shape2, shape3 ] // <-- containing a few elements ...
)

const quadCanvas = (canvas) =>
createCanvas
( canvas.h * 2
, canvas.w * 2
, canvas.bg
, [ canvas, canvas, canvas, canvas ] // <-- rough example
)

// 1 canvas [%*$]

// quadCanvas [%*$][%*$]
// (2x2) [%*$][%*$]


Then our render function could expand to something more like -



const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
switch (elem.Element)
case 'circle': renderCirlce (elem) // <-- break complex tasks into smaller ones
case 'line': renderLine (elem)

case ... // <-- room for as many cases as you need

case 'canvas': render (elem) // <-- recursion! functional!

default: throw Error (`cannot render unknown Element type: $elem.Element`)
// <-- you must handle every scenario in your program



const renderCircle = (circle) =>
...

const renderLine = (circle) =>
...

.... // <-- define element-specific renderers


Hopefully this gets your feet wet and gives you clearer picture of how to think about data and processes in a functional way.






share|improve this answer


















  • 1




    Please note that a lot of this doesn't make a ton of sense in the P5.js context.
    – Kevin Workman
    Nov 11 at 7:22










  • Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
    – Giorgio Martini
    Nov 19 at 16:47










  • No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
    – user633183
    Nov 20 at 3:57










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244329%2fhow-to-remove-mutability-when-creating-an-increasing-value-such-as-a-position%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted










It's absolutely fine in this case.



In your case, you're using a single variable to represent a single value. Since this value changes over time, it makes perfect sense that the variable would change over time.



Generally, I'd be very skeptical of claims that XYZ is always a good idea or always a bad idea. Everything depends on context.






share|improve this answer






















  • What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
    – user633183
    Nov 11 at 5:37










  • @user633183 Yes, all of that is absolutely fine in this context.
    – Kevin Workman
    Nov 11 at 6:23










  • @user633183 I'm not really sure what you mean? Flagging.
    – Kevin Workman
    Nov 11 at 7:14















up vote
1
down vote



accepted










It's absolutely fine in this case.



In your case, you're using a single variable to represent a single value. Since this value changes over time, it makes perfect sense that the variable would change over time.



Generally, I'd be very skeptical of claims that XYZ is always a good idea or always a bad idea. Everything depends on context.






share|improve this answer






















  • What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
    – user633183
    Nov 11 at 5:37










  • @user633183 Yes, all of that is absolutely fine in this context.
    – Kevin Workman
    Nov 11 at 6:23










  • @user633183 I'm not really sure what you mean? Flagging.
    – Kevin Workman
    Nov 11 at 7:14













up vote
1
down vote



accepted







up vote
1
down vote



accepted






It's absolutely fine in this case.



In your case, you're using a single variable to represent a single value. Since this value changes over time, it makes perfect sense that the variable would change over time.



Generally, I'd be very skeptical of claims that XYZ is always a good idea or always a bad idea. Everything depends on context.






share|improve this answer














It's absolutely fine in this case.



In your case, you're using a single variable to represent a single value. Since this value changes over time, it makes perfect sense that the variable would change over time.



Generally, I'd be very skeptical of claims that XYZ is always a good idea or always a bad idea. Everything depends on context.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 10 at 23:51

























answered Nov 10 at 23:22









Kevin Workman

32.9k53967




32.9k53967











  • What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
    – user633183
    Nov 11 at 5:37










  • @user633183 Yes, all of that is absolutely fine in this context.
    – Kevin Workman
    Nov 11 at 6:23










  • @user633183 I'm not really sure what you mean? Flagging.
    – Kevin Workman
    Nov 11 at 7:14

















  • What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
    – user633183
    Nov 11 at 5:37










  • @user633183 Yes, all of that is absolutely fine in this context.
    – Kevin Workman
    Nov 11 at 6:23










  • @user633183 I'm not really sure what you mean? Flagging.
    – Kevin Workman
    Nov 11 at 7:14
















What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
– user633183
Nov 11 at 5:37




What is "absolutely fine"? reassigning xpos? calling noStroke without arguments and discarding its return value? Discarding the return value of ellipse? Declaring variables without const or let or var?
– user633183
Nov 11 at 5:37












@user633183 Yes, all of that is absolutely fine in this context.
– Kevin Workman
Nov 11 at 6:23




@user633183 Yes, all of that is absolutely fine in this context.
– Kevin Workman
Nov 11 at 6:23












@user633183 I'm not really sure what you mean? Flagging.
– Kevin Workman
Nov 11 at 7:14





@user633183 I'm not really sure what you mean? Flagging.
– Kevin Workman
Nov 11 at 7:14













up vote
-1
down vote













This is a really broad question, but I'll give you my advice. Start looking at setup -



function setup () 
createCanvas(300,500) // where is the canvas created?

background(3) // background(3)? 3?
// does this set the background? on what?

bola = createCircle(circleOpts) // this is better
// createCircle accepts an input and it returns a value
// don't forget: const bola = ...




In general, you'll want to design functions that accept inputs and return outputs. Let's even think about the types of inputs and outputs they might have



createCircle : (x: Int, y: Int, r: Int) -> Element

moveCircle : (Element, x: Int, y: Int) -> Element

createCanvas : (h: Int, w: Int, bg: Int, elements: [Element]) -> Canvas

setBackground : (c: Canvas, bg: Int) -> Canvas

draw: (c: Canvas, e: Element) -> Canvas


Let's answer your question broadly here. We will implement createCircle which constructs a simple object. moveCircle will accept a Circle as input, but it will not mutate it -






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





We'll continue implementing more of your program. Each function has sensible parameters and produces an output



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas // <-- similar technique as moveCircle
( canvas.h // we create a new canvas using the canvas's height
, canvas.w // and the canvas's width
, bg // setting the new bg here
, canvas.elements // and keeping the existing canvas's elements
)

const draw = (canvas, element) =>
createCanvas // <-- same technique as above
( canvas.h // ...
, canvas.w // ...
, canvas.bg // same canvas bg this time
, append // append the new element to
( canvas.elements // the canvas's elements
, element
)
)

const append = (xs, x) =>
xs .concat ([ x ]) // <-- immutability everywhere (ie, no .push)


Lastly I'll introduce render. This is our side effect that takes a Canvas and renders it to the screen. A hallmark feature of side-effecting (impure) functions is that they have no return value (null, undefined, or void) -



render: (c: Canvas) -> Void

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)



This just "renders" the Canvas to the console, but the effect is the same. Write to stdout, a file, send it across the network, it doesn't matter; What matters is we kept everything pure up until this point.



Here's what a program might look like that uses our functions above -



const main = () =>
const canvas =
setBackground // set background
( createCanvas (300, 500) // on a 300x500 canvas
, 3 // to bg:3 (yellow?)
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle)) // <-- render is an efffect
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle)) // <-- effect
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2



You can verify the results in your own browser below






const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






I want to briefly revisit createCanvas and change it from -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )


to -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( Element: "canvas", h, w, bg, elements )


This would allow canvases to be composed of other canvases. Designing composable data types is a cornerstone of functional programming -



const canvas =
createCanvas
( 300
, 500
, 0
, [ shape1, shape2, shape3 ] // <-- containing a few elements ...
)

const quadCanvas = (canvas) =>
createCanvas
( canvas.h * 2
, canvas.w * 2
, canvas.bg
, [ canvas, canvas, canvas, canvas ] // <-- rough example
)

// 1 canvas [%*$]

// quadCanvas [%*$][%*$]
// (2x2) [%*$][%*$]


Then our render function could expand to something more like -



const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
switch (elem.Element)
case 'circle': renderCirlce (elem) // <-- break complex tasks into smaller ones
case 'line': renderLine (elem)

case ... // <-- room for as many cases as you need

case 'canvas': render (elem) // <-- recursion! functional!

default: throw Error (`cannot render unknown Element type: $elem.Element`)
// <-- you must handle every scenario in your program



const renderCircle = (circle) =>
...

const renderLine = (circle) =>
...

.... // <-- define element-specific renderers


Hopefully this gets your feet wet and gives you clearer picture of how to think about data and processes in a functional way.






share|improve this answer


















  • 1




    Please note that a lot of this doesn't make a ton of sense in the P5.js context.
    – Kevin Workman
    Nov 11 at 7:22










  • Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
    – Giorgio Martini
    Nov 19 at 16:47










  • No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
    – user633183
    Nov 20 at 3:57














up vote
-1
down vote













This is a really broad question, but I'll give you my advice. Start looking at setup -



function setup () 
createCanvas(300,500) // where is the canvas created?

background(3) // background(3)? 3?
// does this set the background? on what?

bola = createCircle(circleOpts) // this is better
// createCircle accepts an input and it returns a value
// don't forget: const bola = ...




In general, you'll want to design functions that accept inputs and return outputs. Let's even think about the types of inputs and outputs they might have



createCircle : (x: Int, y: Int, r: Int) -> Element

moveCircle : (Element, x: Int, y: Int) -> Element

createCanvas : (h: Int, w: Int, bg: Int, elements: [Element]) -> Canvas

setBackground : (c: Canvas, bg: Int) -> Canvas

draw: (c: Canvas, e: Element) -> Canvas


Let's answer your question broadly here. We will implement createCircle which constructs a simple object. moveCircle will accept a Circle as input, but it will not mutate it -






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





We'll continue implementing more of your program. Each function has sensible parameters and produces an output



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas // <-- similar technique as moveCircle
( canvas.h // we create a new canvas using the canvas's height
, canvas.w // and the canvas's width
, bg // setting the new bg here
, canvas.elements // and keeping the existing canvas's elements
)

const draw = (canvas, element) =>
createCanvas // <-- same technique as above
( canvas.h // ...
, canvas.w // ...
, canvas.bg // same canvas bg this time
, append // append the new element to
( canvas.elements // the canvas's elements
, element
)
)

const append = (xs, x) =>
xs .concat ([ x ]) // <-- immutability everywhere (ie, no .push)


Lastly I'll introduce render. This is our side effect that takes a Canvas and renders it to the screen. A hallmark feature of side-effecting (impure) functions is that they have no return value (null, undefined, or void) -



render: (c: Canvas) -> Void

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)



This just "renders" the Canvas to the console, but the effect is the same. Write to stdout, a file, send it across the network, it doesn't matter; What matters is we kept everything pure up until this point.



Here's what a program might look like that uses our functions above -



const main = () =>
const canvas =
setBackground // set background
( createCanvas (300, 500) // on a 300x500 canvas
, 3 // to bg:3 (yellow?)
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle)) // <-- render is an efffect
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle)) // <-- effect
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2



You can verify the results in your own browser below






const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






I want to briefly revisit createCanvas and change it from -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )


to -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( Element: "canvas", h, w, bg, elements )


This would allow canvases to be composed of other canvases. Designing composable data types is a cornerstone of functional programming -



const canvas =
createCanvas
( 300
, 500
, 0
, [ shape1, shape2, shape3 ] // <-- containing a few elements ...
)

const quadCanvas = (canvas) =>
createCanvas
( canvas.h * 2
, canvas.w * 2
, canvas.bg
, [ canvas, canvas, canvas, canvas ] // <-- rough example
)

// 1 canvas [%*$]

// quadCanvas [%*$][%*$]
// (2x2) [%*$][%*$]


Then our render function could expand to something more like -



const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
switch (elem.Element)
case 'circle': renderCirlce (elem) // <-- break complex tasks into smaller ones
case 'line': renderLine (elem)

case ... // <-- room for as many cases as you need

case 'canvas': render (elem) // <-- recursion! functional!

default: throw Error (`cannot render unknown Element type: $elem.Element`)
// <-- you must handle every scenario in your program



const renderCircle = (circle) =>
...

const renderLine = (circle) =>
...

.... // <-- define element-specific renderers


Hopefully this gets your feet wet and gives you clearer picture of how to think about data and processes in a functional way.






share|improve this answer


















  • 1




    Please note that a lot of this doesn't make a ton of sense in the P5.js context.
    – Kevin Workman
    Nov 11 at 7:22










  • Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
    – Giorgio Martini
    Nov 19 at 16:47










  • No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
    – user633183
    Nov 20 at 3:57












up vote
-1
down vote










up vote
-1
down vote









This is a really broad question, but I'll give you my advice. Start looking at setup -



function setup () 
createCanvas(300,500) // where is the canvas created?

background(3) // background(3)? 3?
// does this set the background? on what?

bola = createCircle(circleOpts) // this is better
// createCircle accepts an input and it returns a value
// don't forget: const bola = ...




In general, you'll want to design functions that accept inputs and return outputs. Let's even think about the types of inputs and outputs they might have



createCircle : (x: Int, y: Int, r: Int) -> Element

moveCircle : (Element, x: Int, y: Int) -> Element

createCanvas : (h: Int, w: Int, bg: Int, elements: [Element]) -> Canvas

setBackground : (c: Canvas, bg: Int) -> Canvas

draw: (c: Canvas, e: Element) -> Canvas


Let's answer your question broadly here. We will implement createCircle which constructs a simple object. moveCircle will accept a Circle as input, but it will not mutate it -






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





We'll continue implementing more of your program. Each function has sensible parameters and produces an output



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas // <-- similar technique as moveCircle
( canvas.h // we create a new canvas using the canvas's height
, canvas.w // and the canvas's width
, bg // setting the new bg here
, canvas.elements // and keeping the existing canvas's elements
)

const draw = (canvas, element) =>
createCanvas // <-- same technique as above
( canvas.h // ...
, canvas.w // ...
, canvas.bg // same canvas bg this time
, append // append the new element to
( canvas.elements // the canvas's elements
, element
)
)

const append = (xs, x) =>
xs .concat ([ x ]) // <-- immutability everywhere (ie, no .push)


Lastly I'll introduce render. This is our side effect that takes a Canvas and renders it to the screen. A hallmark feature of side-effecting (impure) functions is that they have no return value (null, undefined, or void) -



render: (c: Canvas) -> Void

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)



This just "renders" the Canvas to the console, but the effect is the same. Write to stdout, a file, send it across the network, it doesn't matter; What matters is we kept everything pure up until this point.



Here's what a program might look like that uses our functions above -



const main = () =>
const canvas =
setBackground // set background
( createCanvas (300, 500) // on a 300x500 canvas
, 3 // to bg:3 (yellow?)
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle)) // <-- render is an efffect
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle)) // <-- effect
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2



You can verify the results in your own browser below






const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






I want to briefly revisit createCanvas and change it from -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )


to -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( Element: "canvas", h, w, bg, elements )


This would allow canvases to be composed of other canvases. Designing composable data types is a cornerstone of functional programming -



const canvas =
createCanvas
( 300
, 500
, 0
, [ shape1, shape2, shape3 ] // <-- containing a few elements ...
)

const quadCanvas = (canvas) =>
createCanvas
( canvas.h * 2
, canvas.w * 2
, canvas.bg
, [ canvas, canvas, canvas, canvas ] // <-- rough example
)

// 1 canvas [%*$]

// quadCanvas [%*$][%*$]
// (2x2) [%*$][%*$]


Then our render function could expand to something more like -



const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
switch (elem.Element)
case 'circle': renderCirlce (elem) // <-- break complex tasks into smaller ones
case 'line': renderLine (elem)

case ... // <-- room for as many cases as you need

case 'canvas': render (elem) // <-- recursion! functional!

default: throw Error (`cannot render unknown Element type: $elem.Element`)
// <-- you must handle every scenario in your program



const renderCircle = (circle) =>
...

const renderLine = (circle) =>
...

.... // <-- define element-specific renderers


Hopefully this gets your feet wet and gives you clearer picture of how to think about data and processes in a functional way.






share|improve this answer














This is a really broad question, but I'll give you my advice. Start looking at setup -



function setup () 
createCanvas(300,500) // where is the canvas created?

background(3) // background(3)? 3?
// does this set the background? on what?

bola = createCircle(circleOpts) // this is better
// createCircle accepts an input and it returns a value
// don't forget: const bola = ...




In general, you'll want to design functions that accept inputs and return outputs. Let's even think about the types of inputs and outputs they might have



createCircle : (x: Int, y: Int, r: Int) -> Element

moveCircle : (Element, x: Int, y: Int) -> Element

createCanvas : (h: Int, w: Int, bg: Int, elements: [Element]) -> Canvas

setBackground : (c: Canvas, bg: Int) -> Canvas

draw: (c: Canvas, e: Element) -> Canvas


Let's answer your question broadly here. We will implement createCircle which constructs a simple object. moveCircle will accept a Circle as input, but it will not mutate it -






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





We'll continue implementing more of your program. Each function has sensible parameters and produces an output



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas // <-- similar technique as moveCircle
( canvas.h // we create a new canvas using the canvas's height
, canvas.w // and the canvas's width
, bg // setting the new bg here
, canvas.elements // and keeping the existing canvas's elements
)

const draw = (canvas, element) =>
createCanvas // <-- same technique as above
( canvas.h // ...
, canvas.w // ...
, canvas.bg // same canvas bg this time
, append // append the new element to
( canvas.elements // the canvas's elements
, element
)
)

const append = (xs, x) =>
xs .concat ([ x ]) // <-- immutability everywhere (ie, no .push)


Lastly I'll introduce render. This is our side effect that takes a Canvas and renders it to the screen. A hallmark feature of side-effecting (impure) functions is that they have no return value (null, undefined, or void) -



render: (c: Canvas) -> Void

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)



This just "renders" the Canvas to the console, but the effect is the same. Write to stdout, a file, send it across the network, it doesn't matter; What matters is we kept everything pure up until this point.



Here's what a program might look like that uses our functions above -



const main = () =>
const canvas =
setBackground // set background
( createCanvas (300, 500) // on a 300x500 canvas
, 3 // to bg:3 (yellow?)
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle)) // <-- render is an efffect
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle)) // <-- effect
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2



You can verify the results in your own browser below






const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






I want to briefly revisit createCanvas and change it from -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )


to -



const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( Element: "canvas", h, w, bg, elements )


This would allow canvases to be composed of other canvases. Designing composable data types is a cornerstone of functional programming -



const canvas =
createCanvas
( 300
, 500
, 0
, [ shape1, shape2, shape3 ] // <-- containing a few elements ...
)

const quadCanvas = (canvas) =>
createCanvas
( canvas.h * 2
, canvas.w * 2
, canvas.bg
, [ canvas, canvas, canvas, canvas ] // <-- rough example
)

// 1 canvas [%*$]

// quadCanvas [%*$][%*$]
// (2x2) [%*$][%*$]


Then our render function could expand to something more like -



const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
switch (elem.Element)
case 'circle': renderCirlce (elem) // <-- break complex tasks into smaller ones
case 'line': renderLine (elem)

case ... // <-- room for as many cases as you need

case 'canvas': render (elem) // <-- recursion! functional!

default: throw Error (`cannot render unknown Element type: $elem.Element`)
// <-- you must handle every scenario in your program



const renderCircle = (circle) =>
...

const renderLine = (circle) =>
...

.... // <-- define element-specific renderers


Hopefully this gets your feet wet and gives you clearer picture of how to think about data and processes in a functional way.






const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle // <-- moveCircle creates a new circle
( circle.x + x // using the circle's x value added to the new x
, circle.y + y // and the circle's y value added to the new y
, circle.r // the circle's radius, r, is unchanged
)

const circle =
createCircle (0, 0, 2)

const movedCircle =
moveCircle (circle, -3, 3) // <-- circle is NOT mutated

console.log
( circle // Element: "circle", x: 0, y: 0, r: 2
, movedCircle // Element: "circle", x: -3, y: 3, r: 2
, circle // Element: "circle", x: 0, y: 0, r: 2
)





const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()





const createCanvas = (h = 100, w = 100, bg = 0, elements = ) =>
( h, w, bg, elements )

const setBackground = (canvas, bg) =>
createCanvas
( canvas.h
, canvas.w
, bg
, canvas.elements
)

const createCircle = (x, y, r) =>
( Element: "circle", x, y, r )

const moveCircle = (circle, x, y) =>
createCircle
( circle.x + x
, circle.y + y
, circle.r
)

const append = (xs, x) =>
xs .concat ([ x ])

const draw = (canvas, element) =>
createCanvas
( canvas.h
, canvas.w
, canvas.bg
, append
( canvas.elements
, element
)
)

const render = (canvas) =>
console.log (`creating $canvas.wx$canvas.h with bg:$canvas.bg`)
for (const elem of canvas.elements)
console.log (`rendering`, elem)


const main = () =>
const canvas =
setBackground
( createCanvas (300, 500)
, 3
)

const circle =
createCircle (0, 0, 2)

render (draw (canvas, circle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: 0, y: 0, r: 2

const movedCircle =
moveCircle (circle, -3, 3)

render (draw (canvas, movedCircle))
// creating 500x300 with bg:3
// rendering Element: "circle", x: -3, y: 3, r: 2


main ()






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 11 at 7:00

























answered Nov 11 at 5:35









user633183

66.7k21130172




66.7k21130172







  • 1




    Please note that a lot of this doesn't make a ton of sense in the P5.js context.
    – Kevin Workman
    Nov 11 at 7:22










  • Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
    – Giorgio Martini
    Nov 19 at 16:47










  • No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
    – user633183
    Nov 20 at 3:57












  • 1




    Please note that a lot of this doesn't make a ton of sense in the P5.js context.
    – Kevin Workman
    Nov 11 at 7:22










  • Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
    – Giorgio Martini
    Nov 19 at 16:47










  • No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
    – user633183
    Nov 20 at 3:57







1




1




Please note that a lot of this doesn't make a ton of sense in the P5.js context.
– Kevin Workman
Nov 11 at 7:22




Please note that a lot of this doesn't make a ton of sense in the P5.js context.
– Kevin Workman
Nov 11 at 7:22












Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
– Giorgio Martini
Nov 19 at 16:47




Thank you very much for your great answer.. but its not very relevant in the context of p5js... and does not realy answer the question.
– Giorgio Martini
Nov 19 at 16:47












No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
– user633183
Nov 20 at 3:57




No worries. Functional programming is not relevant in the context of p5js. I never heard of it before answering this question. I hope you were able to learn something about functional programming anyway.
– user633183
Nov 20 at 3:57

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244329%2fhow-to-remove-mutability-when-creating-an-increasing-value-such-as-a-position%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Barbados

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3