2008-11-22 8 views
5

J'apprends la programmation fonctionnelle, et j'ai essayé de résoudre quelques problèmes dans un style fonctionnel. Une chose que j'ai vécue, en divisant mon problème en fonctions, était qu'il me semblait avoir deux options: utiliser plusieurs fonctions disparates avec des listes de paramètres similaires, ou utiliser des fonctions imbriquées qui, comme fermetures, peuvent simplement faire référence à des liaisons dans la fonction parent. Bien que j'aie fini avec la seconde approche, parce qu'elle rendait les appels de fonction plus petits et qu'elle semblait "mieux" sentir, d'après ma lecture, il me semble qu'il me manque peut-être un des points principaux de la programmation fonctionnelle, en ce sens cela semble "side-effecty"? Maintenant accordé, ces fonctions imbriquées ne peuvent pas modifier les liaisons externes, car le langage que j'utilisais empêche cela, mais si vous regardez chaque fonction interne individuelle, vous ne pouvez pas dire "donné les mêmes paramètres, cette fonction retournera les mêmes résultats" parce qu'ils utilisent les variables de la portée parent ... ai-je raison?Fonctions imbriquées: Utilisation incorrecte des effets secondaires?

Quelle est la manière souhaitable de procéder?

Merci!

Répondre

2

Les fonctions d'imbrication sont un excellent moyen de répartir le travail dans de nombreuses fonctions. Ce n'est pas vraiment "side-effecty"; Si cela aide, pensez aux variables capturées comme des paramètres implicites.

Un exemple où les fonctions imbriquées sont utiles consiste à remplacer les boucles. Les paramètres de la fonction imbriquée peuvent agir comme des variables d'induction qui accumulent des valeurs. Un exemple simple:

let factorial n = 
    let rec facHelper p n = 
     if n = 1 then p else facHelper (p*n) (n-1) 
    in 
    facHelper 1 n 

Dans ce cas, il ne fait pas vraiment de sens de déclarer une fonction comme facHelper globalement, étant donné que les utilisateurs ne devraient pas avoir à se soucier du paramètre p. Notez toutefois qu'il peut être difficile de tester individuellement des fonctions imbriquées, car elles ne peuvent pas être référencées en dehors de leur parent.

+0

facHelper ne fait référence à aucune valeur externe - elle est toujours purement fonctionnelle. –

3

La programmation fonctionnelle n'est pas tout-ou-rien. Si imbriquer les fonctions a plus de sens, j'irais avec cette approche. Cependant, si vous voulez vraiment que les fonctions internes soient purement fonctionnelles, passez explicitement tous les paramètres nécessaires.

Voici un petit exemple dans le schéma:

(define (foo a) 
    (define (bar b) 
    (+ a b))  ; getting a from outer scope, not purely functional 
    (bar 3)) 

(define (foo a) 
    (define (bar a b) 
    (+ a b))  ; getting a from function parameters, purely functional 
    (bar a 3)) 


(define (bar a b) ; since this is purely functional, we can remove it from its 
    (+ a b))  ; environment and it still works 

(define (foo a) 
    (bar a 3)) 

Personnellement, je partirais avec la première approche, mais soit fonctionnent aussi bien.

1

Considérez ce qui suit (pièce) extrait Haskell:

putLines :: [String] -> IO() 
putLines lines = putStr string 
    where string = concat lines 

string est une limite appelée localement constante. Mais n'est-ce pas aussi une fonction ne prenant aucun argument qui se referme sur lines et est donc référentiellement intransparent? (Dans Haskell, les constantes et les fonctions nulles sont en effet indiscernables!) Considérez-vous le code ci-dessus "side-effecty" ou non fonctionnel à cause de cela?

Questions connexes