<!--
Por que evitar entrada/saida de dados em funções?
http://saw.atp.usp.br/mod/page/view.php?id=
-->

<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/QAPage">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Por que evitar entrada/saida de dados em funções?</title>
  <style type="text/css">
   .tbCodeLinCol { border-collapse:collapse; }
   .tbCodeLinCol th { background-color:#8aaada; }
   .tbCodeLinCol td, .tbCodeLinCol th { padding:5px;border:1px solid #000; font: 10px/12px Arial, Helvetica, sans-serif; }
   .tbCode td, .tb th { border: 0; font: 10px/12px Arial, Helvetica, sans-serif; }
   .tableCd { border-collapse:collapse; }
   .thBg th { background-color:#8aaada; }
   /* .trCd td, .tbCd td, .tbCd th { vertical-align: top; padding:5px; border-right:1px solid #000; font-family: courier } */
   .trCd td, .tbCd td, .tbCd th { vertical-align: top; padding:5px; border-right:1px solid #000; border-bottom:1px solid #000; font-family: courier }
   .cmd { color: #0000AA; }
   .fnc { color: #00AAAA; }
   .head { color: #000000; }
   .var { color: #009A00; }
   .tipo { color: #005A5A; }
   .com { color: #AA0000; }
   .def { color: #008181; font-weight: bold; } /* definicao */   
   .versao { font-size: .6em; }
  </style>

</head>

<body>

<span style="color: #0055AA;font-size:1.2em"><b>Por que evitar entrada/saida de dados em funções</b></span>
      
<p>
Para explicar as razões pelas quais deve-se <b>evitar comandos de entrada e de saída dentro da definição de uma função</b>,
devemos primeiro enfatizar o que é a uma função em linguagens como <i>C</i> ou  <i>Python</i>:
<ul>
  <li>é um código que recebe seus <em>dados de entrada</em> a partir de uma <i>lista de parâmetros</i> (<i class="def">parâmetros formais</i>);</li>
  <li>é um código que processa os dados de entrada e geralmente devolve algum valor como resposta (em seu comando <tt class="cmd">return</tt>);</li>
  <li>é um código que pode ser invocado a partir de outros trechos do programa, que providenciam os valores para os parâmetros
      (<i class="def">parâmetros efetivos</i>).</li>
</ul>
</p>

<p>
Desse modo, usando como exemplo a <i>função fatorial</i> (<i>fat(0)=1</i> e <i>fat(n)=n*fat(n-1), n&gt;0</i>), a razão para
se evitar comandos de entrada e de saída dentro da definição da função pode ser resumida em:
<ul>
  <li><i>Facilita o reúso de código</i>, ou seja, sempre que precisar de um algoritmo que compute o fatorial,
      basta copiar o código que já implementou (e testou);</li>
  <li><i>Facilita o desenvolvimento de programas maiores</i>, pois pode-se agrupar os blocos lógicos que tenham um propósito bem definido como
      uma função.</li>
</ul>
</p>

<p>
A fim de ficar mais clara a vantagem de <i>passar os valores via parâmetro</i>, pense na implementação <i>errônea</i> da função
<tt class="var">fat</tt>, suponha que em seu código tenha sido usado um comando para <i>leitura</i> (via teclado) dos dados.
Então, se precisar computar a combinação de <tt>n</tt>, tomados <tt>k</tt> a <tt>k</tt> (<i>C<sub>n,k</sub>=n!/((n-k)!k!)</i>),
esse valor <b>não</b> poderá ser computado usando a expressão seguinte (com chamada à função <tt class="var">fat</tt>):
<tt class="var">fat(n)/(fat(n-k)fat(k))</tt>.
<br/>
Por que mesmo? Porque, os valores a partir dos quais desejamos saber a combinação já são <b>dados</b>, <b>não</b> faz sentido obrigar
o usuário a digitar os valores de <tt>n</tt>, de <tt>n-k</tt> e de <tt>k</tt> (além disso ele pode digitar errado!).
</p>

<p>
Assim, nos exercícios que apresentam o conceito de função (portanto envolvendo um bloco lógico com propósito bem definido),
exigiremos que o aprendiz <b>não</b> use comandos de entrada ou de saída de dados <b>dentro da função</b>.
Com isso esperamos que ele adquira <i>bons hábitos de programação</i>.
</p>

<p>
<!-- F<sub>0</sub>=1, F<sub>1</sub>=1, F<sub>k</sub> = F<sub>k-1</sub> + F<sub>k-2</sub>, k&gt;2 -->  
Entretanto, existem as exceções, exemplos nos quais é útil usar comando de entrada ou de saída dentro da função. Ilustraremos
o caso de utilidade de um comando de saída dentro da função, isso ocorre se desejamos computar (e imprimir) os <tt>n</tt> primeiros termos da
<i title="F_{0}=1, F_{1}=1, F_{k} = F_{k-1} + F_{k-2}, k&gt;1">sequência de Fibonacci</i>.
Então, naturalmente precisaremos do comando de impressão/saída e como isso pode ser feito para qualquer
<tt>n</tt> é adequado agrupar esse código na forma de um procedimento separado (no caso uma função <b>sem</b> valor de retorno).
<br/>
Porém se o objetivo fosse conhecer apenas o termo <tt>n</tt> da sequência, a função <b>não deveria ter o comando de saída</b>.
</p>

<p>
Uma última observação sobre os exercícios envolvendo funções. <b>O programa principal sempre deve ter ao menos um comando para entrada
e ao menos um para saída de dados</b>. Sem eles não seria possível testar se a função do exercício foi implementada corretamente ou não.
</p>

<span style="color: #0055AA;font-size:1.1em">Exemplo 1. Dados naturais <tt>n</tt> e <tt>k</tt>, computar a combinação de <tt>n</tt> <tt>k-a-k</tt></span>

<p>
Suponha que precisemos fazer um program para computar
quantas são as combinações de <tt>n</tt> termos combinados <tt>k</tt>-a-<tt>k</tt>, ou seja, tendo <tt>n</tt> elementos,
desejamos saber de quantos modos distintos podemos formar grupos com <tt>k</tt> dos elementos.
</p>

<p>
Esse conceito aparece em <i>probabilidade</i> e em <i>combinatória</i>, sabemos que esta combinação corresponde ao agrupamentos de
elementos nos quais a ordem não importa (tanto faz a ordem dos <tt>k</tt> elementos do tipo <tt>a</tt>) e que a fórmula que fornece
o total desses subconjuntos é a seguinte:
<center><a href="https://en.wikipedia.org/wiki/Binomial_theorem" title="explicacao mais detalhada na WikiPedia">C(n,k) = n! / ((n-k)! k!)</a>.</center>
</p>

<p>
Por exemplo, combinar <tt>6</tt> valores distintos, tomados <tt>2</tt> a <tt>2</tt> resulta <tt>15=6!/((6-2)!2!)=6!/(4!2!)</tt>, que
são os <tt>15</tt> subconjuntos: 
 <tt>(6,5)</tt>, <tt>(6,4)</tt>, <tt>(6,3)</tt>, <tt>(6,2)</tt>, <tt>(6,1)</tt>, 
 <tt>(5,4)</tt>, <tt>(5,3)</tt>, <tt>(5,2)</tt>, <tt>(5,1)</tt>,
 <tt>(4,3)</tt>, <tt>(4,2)</tt>, <tt>(4,1)</tt>,
 <tt>(3,2)</tt>, <tt>(3,1)</tt>,
 <tt>(2,1)</tt>.
</p>

<p>
Assim, existem duas possibilidades de implementar esse código, uma implementando a função fatorial (<tt>fat(n)</tt>) que seria
invocada três vezes pelo programa principal (com algo como  <tt>imprima(fat(n) / (fat(k) * fat(n-k))</tt>.
Outra possibilidade é implementar também o cômputo de <tt>fat(n) / (fat(k) * fat(n-k))</tt> também como uma função.
Apesar dessa segunda possibilidade não ajudar tanto na organização do código (pois a segunda função (<tt>comb(n,k)</tt>) seria muito
simples, ilustraremos dessa forma por ela usar função chamando função que chama função (a principal chama <tt>comb(n,k)</tt> e essa
chama <tt>fat(n)</tt>).
Veja como ficaria o código em uma <i>pseudo-linguagem</i> de programação:
<pre>int fat(n) { //# estou supondo que o valor digitado pelo usuario seja um natural maior ou igual a 0 (n>=0)
  valfat = 1;
  cont = 2;
  enquanto (cont&lt;=n) { //# continue computando enquanto nao chegar ao valor cont==n
    valfat = valfat * cont;
    cont = cont + 1;	    
    }
  devolva valfat;
  }
int comb(n, k) {
  devolva fat(n) / (fat(n-k)*fat(k));
  }
principal() {
  declara_inteiros N, k; //# note que os nomes de variaveis daqui tem relacao NULA com os usados em 'fat'
  declara_inteiros a, b, c; //# para uma segunda versao
  leia(N, k); //# leia 2 valores naturais e armazene-os respectivamente em N e em k (espera-se que digite N>=k)
  //# pode-se invocar seguidamente fat 3 vezes como abaixo:
  imprima(comb(N,k);
  //# pode-se invocar a funcao fat 3 vezes e armazenar cada resultado e depois "imprimir"
  a = fat(N);
  b = fat(k);
  c = fat(N-k);
  imprima(a/( b * c))); //# este exemplo e' ilustrado na figura abaixo
  }</pre>
</p>

<center><img src="img/exemplo_exec_funcao.jpg" title="exemplo de execucao da funcao"/>
</center>

<p>
Novamente para enfatizar as desvantagens de usar leitura ou impressão dentro de funções, 
procure implementar o código acima, em sua linguagem favorita, e colocar nele comandos para
leitura ou saída dentro da função <tt>fat(n)</tt>, como discutido abaixo.
</p>


<span style="color: #0055AA;font-size:1.1em">Observação 1. Vantagem de uso de função sem comandos de entrada/saída - combinação n, k-a-k</span>

<p>
Note que se dentro da função <tt>fat</tt> houvesse um comando do tipo <tt>leia(n);</tt>
a função NÃO poderia ser usada, pois ao ser invocada as 3 vezes, em cada uma delas exigiria que o
usuário digitasse novamente o valor para <tt>N</tt> inicialmente (estragando o valor de <tt>N</tt> passado para a função),
depois exigiria a digitação novamente do <tt>k</tt> e por último haveria o absurdo de exigir que o usuário
digitasse o valor para <tt>N-k</tt>.
</p>  

<p>
De forma análoga, se a função <tt>fat</tt> tivesse algum comando de saída, ao usar a função 3 vezes, o usuário
receberia informações confusas: ele deseja a combinação de <tt>n</tt> combinados <tt>k</tt>-a-<tt>k</tt>, mas
receberia 4 infomações (<tt>n!</tt>, <tt>k!</tt>, <tt>(n-k)!</tt> e <tt>n!/(k! (n-k)!))))</tt>).
</p>

<span style="color: #0055AA;font-size:1.1em">Observação 2. Propriedade interessante de C(n,k) - Triângulo de Pascal</span>

<p>
Se rodarmos este programa seguidamente, na ordem das colunas (primeiro a única entrada de <tt>Entradas 0</tt>, depois a primeira
linha de <tt>Entradas 1</tt>, depois sua segunda linha e assim por diante até a última linha de <tt>Entradas 4</tt>) e
agruparmos as saídas de cada coluna em uma única linha, obteremos a tabela na última coluna abaixo (<tt>Saídas (cada linha um dos blocos de entradas)</tt>).
Destacamos três dos valores para mostrar a relação do
<a href="https://en.wikipedia.org/wiki/Pascal%27s_triangle" title="seguir para WikiPedia">Triângulo de Pascal</a>

<table class="tableCd">
 <tr class="trCd" valign="top">
   <td>Linhas &nbsp;&nbsp;</td><td>Entradas 0&nbsp;&nbsp;</td><td>Entradas 1&nbsp;&nbsp;</td><td>Entradas 2&nbsp;&nbsp;</td>
   <td>Entradas 3&nbsp;&nbsp;</td><td>Entradas 4&nbsp;&nbsp;</td>
   <td>Saídas (cada linha um dos blocos de entradas)</td></tr>
 <tr class="trCd" valign="top"><td><pre>   0
   1
   2
   3
   4</pre></td><td><pre> 1   0</pre></td>   <td><pre> 1   1
 1   0</pre></td><td><pre> 2   0
 2   1
 2   2</pre></td><td><pre> 3   0
 3   1
 3   2
 3   3</pre></td><td><pre> 4   0
 4   1
 4   2
 4   3
 4   4</pre></td><td><pre> 1
 1   1
 1   2   1
[1] [3]   3   1
 1  [4]   6   4   1</pre></td></tr></table></p>

<p>
Examinando as saídas (ũltima coluna) notamos uma propriedade interessante:
o elemento da linha <tt>n+1</tt>, coluna <tt>k+1</tt> = o elemento da linha <tt>n</tt>, coluna <tt>k</tt> + o elemento da linha <tt>n</tt>, coluna </tt>k+1</tt>.
Veja por exemplo, a última linha, linha <tt>4</tt>: o segundo elemento = <tt>4</tt> = <tt>1 + 3</tt> (da linha acima).
</p>

<!--
<pre>1 0
---
1 1
1 0
---
2 0
2 1
2 2
---
3 0
3 1
3 2
3 3
---
4 0
4 1
4 2
4 3
4 4</pre>
-->

<!-- https://pt.wikipedia.org/wiki/Produtos_not%C3%A1veis -->

<!--
<span style="color: #0055AA;font-size:1.1em">Exemplo 2. Coeficientes da expansão do produto notável <tt>(a+b)^n</tt></span>

<p>
Suponhamos que precisemos fazer um program que computa os termos dos coeficientes da expansão de <tt>(a+b)^n</tt>.
Ou seja, desejamos um programa que dado <tt>n</tt> liste quantos termos do tipo <tt>a^i x b^j</tt> existe, para cada
<tt>i</tt> e cada <tt>j</tt> tais que <tt>i+j=n</tt>.

  o valor da combinação de <i>N</i> tomado <i>k</i> a <i>k</i>, ou seja,
C(N,k) = N! / ( k! (N-k)!).
Para isso percebe-se que é necessário implementar o cômputo de fatorial que será utilizado 3 vezes.
Para facilitar a compreensão, podemos escrever um código com 3 variáveis auxiliares para armazenar, respectivamente,
<i>N!</i>, <i>k!</i> e <i>(N-k)!</i>.
</p>

<pre>(a+b)^0                                                         = 1 a^0 b^0
(a+b)^1 = (a+b) (0 a^0 b^0 + 0 a^0 b^0)                         = 1 a^1 b^0 + 1 a^0 b^0 
(a+b)^2 = (a+b) (1 a^1 b^0 + 0 a^0 b^1)                         = 1 a^2 b^0 + 2 a^1 b^1 + 1 a^0 b^2
(a+b)^3 = (a+b) (1 a^2 b^0 + 2 a^1 b^1 + 1 a^0 b^2)             = 1 a^3 b^0 + 3 a^2 b^1 + 3 a^1 b^2 + 1 a^0 b^3
(a+b)^4 = (a+b) (1 a^3 b^0 + 3 a^2 b^1 + 3 a^1 b^2 + 1 a^0 b^3) = 1 a^4 b^0 + 4 a^3 b^1 + 6 a^2 b^2 + 4 a^1 b^3 + 1 a^0 b^3a
</pre>
<pre>1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
</pre>
-->

<p>
Leônidas de Oliveira Brandão<br/>
http://line.ime.usp.br
<!--
 2017/04/06: primeira versao
 2019/04/07: versao 2 (acrescentado novos paragrafos, melhorando explicacoes e frases)
-->
</p>
</body>