Qu'est ce qu'un remplacement fonctionnel pour if-then?
J'ai appris F# et de la programmation fonctionnelle et d'essayer de faire les choses de la façon fonctionnelle. Cependant, quand il s'agit de la réécriture du code, j'avais déjà écrit en C#, je me retrouve bloqué à un simple if-then (ceux qui ne font qu'une chose, de ne pas renvoyer une valeur). Je sais que vous pouvez en sortir en F#:
if expr then do ()
Cependant, je pensais que c'était un impératif approche de codage? Peut-être que je n'ai pas assez appris sur la programmation fonctionnelle, mais il ne semble pas fonctionnel pour moi. J'ai pensé que l'approche fonctionnelle a été de composer des fonctions et des expressions, pas simplement d'exécuter des instructions l'une après l'autre, qui est ce que si-alors semble encourager.
Donc, suis-je raté quelque chose et si alors est parfaitement bien dans le monde fonctionnelle? Si non, quel est l'équivalent fonctionnel d'une telle déclaration? Comment pourrais-je prendre un " si-alors et tournez-il fonctionnel?
Edit: j'ai peut-ai posé la mauvaise question (désolé, encore assez nouveau à la programmation fonctionnelle): prenons un exemple concret qui m'a même demander ceci:
if not <| System.String.IsNullOrWhiteSpace(data) then do
let byteData = System.Text.Encoding.Unicode.GetBytes(data)
req.ContentLength <- int64 byteData.Length
let postStream : System.IO.Stream = req.GetRequestStream()
postStream.Write(byteData, 0, byteData.Length)
postStream.Flush()
postStream.Dispose()
Le corps de cette si-alors ne retourne rien, mais je ne sais pas comment je pourrais le rendre plus fonctionnel (si c'est encore possible). Je ne sais pas la bonne technique pour minimiser code impératif. Étant donné F#'s de la nature, il est assez facile de simplement transporter mon C# directement, mais je vais avoir des difficultés tournant fonctionnelle. Chaque fois que j'atteins un tel si l'instruction en C#, et je suis en train de le transporter à F#, je vous découragez pas que je ne peux pas penser à un moyen de rendre le code plus fonctionnelle.
- Le code dans votre édition est impératif de nature, vous êtes le chaînage de plusieurs actions, pas le calcul d'une valeur. F# on ne peut pas vous aider à le rendre plus fonctionnel, mais il fournit des outils pour isoler les effets secondaires et de les rendre plus visibles.
Vous devez vous connecter pour publier un commentaire.
Un point important qui n'a pas été mentionné jusqu'à présent est la différence entre
if .. then .. else
etif .. then
sanselse
branche.If
dans les langages fonctionnelsL'interprétation fonctionnelle de
if
est que c'est une expression qui renvoie une valeur. Pour évaluer la valeur deif c then e1 else e2
vous d'évaluer l'état dec
et ensuite évaluere1
oue2
, en fonction de l'état. Cela vous donne le résultat de laif .. then .. else
.Si vous avez juste
if c then e
, alors vous ne savez pas quel sera le résultat de l'évaluation doit être sic
estfalse
, car il n'est paselse
branche! La suite n'a clairement aucun sens:En F#, des expressions qui ont des effets secondaires comme
printf "hi"
retourner une valeur spéciale de typeunit
. Le type n'a qu'une seule valeur (écrit que()
) et vous pouvez donc écrireif
qui fait un effet dans un seul cas:Cette évalue toujours à
unit
, mais dans letrue
branche, il exerce également des effets secondaires. Dans lefalse
branche, elle retourne ununit
valeur. En F#, vous n'avez pas à écrire leelse ()
peu par la main, mais sur le plan conceptuel, il est toujours là. Vous pouvez écrire:Concernant votre exemple supplémentaire
Le code ressemble parfaitement bien pour moi. Lorsque vous avez à traiter avec l'API qui est impératif (comme beaucoup de la .Bibliothèques NET), alors la meilleure option est d'utiliser l'impératif fonctionnalités comme
if
avec ununit
-le retour de la branche.Vous pouvez utiliser différents réglages, à l'instar de représenter vos données à l'aide de
option<string>
(au lieu de simplementstring
avecnull
ou une chaîne vide). De cette façon, vous pouvez utiliserNone
pour représenter des données manquantes et de toute autre chose serait d'entrée valide. Ensuite, vous pouvez utiliser certaines fonctions d'ordre supérieur pour le travail avec des options, telles queOption.iter
, qui appelle une fonction donnée s'il existe une valeur:Ce n'est pas vraiment moins impératif, mais il est plus déclaratif, parce que vous n'avez pas à écrire le
if
vous-même. BTW: je recommande également à l'aide deuse
si vous voulezDispose
objet auotmatically.Il n'y a rien de mal si-alors dans monde fonctionnelle.
Votre exemple est en fait similaire à
let _ = expr
depuisexpr
a des effets secondaires et que nous ignorons sa valeur de retour. Un exemple plus intéressant est:qui est équivalent à:
si nous utilisons le pattern matching.
Lorsque la condition est simple ou il y a seulement une expression conditionnelle, si-alors est plus lisible que le pattern matching. Il est d'ailleurs intéressant de noter que tout dans la programmation fonctionnelle est l'expression. Donc
if cond then expr
est en fait le raccourci deif cond then expr else ()
.Si-alors lui-même n'est pas impératif, à l'aide de si-alors qu'un énoncé est un impératif façon de penser. De mon expérience, de la programmation fonctionnelle est plus sur la façon de penser que le béton des flux de contrôle dans les langages de programmation.
EDIT:
Votre code est totalement lisible. Quelques points mineurs sont de se débarrasser de la redondante
do
mot-clé, type d'annotation et depostStream.Dispose()
(en utilisantuse
mot-clé):do
a ses rôles de signalisation des fragments de code qui ont des effets secondaires et la création d'un nouveau champ d'application (c'est important quand va avecusing
fonction).Ce n'est pas le cas-expression qui est impératif, c'est ce qui se passe dans le si-expression. Par exemple,
let abs num = if num < 0 then -num else num
est totalement fonctionnelle à écrire la fonction abs. Elle prend un argument et retourne une transformation de cet argument, sans effets secondaires. Mais quand vous avez de code", qui ne fait qu'une chose, de ne pas renvoyer une valeur," puis vous écrivez quelque chose qui n'est pas purement fonctionnelle. L'objectif de la programmation fonctionnelle est de réduire la part du programme qui peut être décrit de cette façon. La façon dont vous écrivez votre conditionnelles est tangentielle.Dans le but de rédiger un code complexe, vous avez besoin de branche à un certain point. Il y a un nombre très limité de façons que vous pouvez faire, et tous d'entre eux exigent une logique de flux à travers une section de code. Si vous voulez éviter d'utiliser des if/then/else, il est possible de tricher avec la boucle/tout/répétition - mais qui feront de votre code beaucoup moins raisonnable de conserver et de les lire.
De la programmation fonctionnelle ne signifie pas que vous ne devriez pas exécuter des instructions l'une après l'autre - cela signifie simplement que vous ne devriez pas avoir un mutable état. Chaque fonction doit se comporter de manière fiable la même façon à chaque fois qu'elle est appelée. Toutes les différences dans la façon dont les données sont traitées par elle doivent être pris en compte par les données qui est transmis, à la place de certains de déclenchement qui est caché à tout ce qui est de l'appel de la fonction.
Par exemple, si nous avons une fonction
foo(int, bool)
qui renvoie à quelque chose de différent selon quebool
est vrai ou faux, il n'y aura presque certainement être unif
déclaration quelque part dansfoo()
. C'est parfaitement légitime. Ce n'est PAS légitime, est de disposer d'une fonctionfoo(int)
qui renvoie à quelque chose de différent en fonction de si oui ou non c'est la première fois qu'elle est appelée dans le programme. C'est une 'dynamique' de la fonction et cela rend la vie difficile pour quiconque de maintenir le programme.Il est considéré comme fonctionnel si votre
if
déclaration a une valeur de retour et n'a pas d'effets secondaires.Supposons que vous vouliez écrire l'équivalent de:
if(x > 3) n = 3; else n = x;
Au lieu de cela, vous utilisez l'instruction de retour de la commande if:
let n = (if x > 3 then 3 else x)
Cette hypothétique
if
est soudainement fonctionnel car il n'a pas d'effets secondaires; il ne renvoie une valeur. Pensez à elle comme si c'était la opérateur ternaire dans certaines langues:int n = x>3?3:x;
e ? e : e
opérateur est généralement appelé opérateur conditionnel. Un opérateur ternaire est un opérateur qui prend trois arguments.a ? b : c
est appelé ternaire.Il y a deux observations qui peuvent les aider dans la transition de l'impératif fonctionnel ("tout est une expression") de programmation:
unit
est une valeur, tandis qu'une expression de retournervoid
en C# est considérée comme une déclaration. C'est, C# fait une distinction entre les déclarations et les expressions. En F# tout est une expression.En C# les valeurs peuvent être ignorés; en F#, ils ne peuvent donc pas fournir un niveau plus élevé de sécurité de type. Cette clarté rend F# programmes plus faciles à comprendre et offre plus de garanties.
Mes excuses pour ne pas connaître de F#, mais ici, c'est une solution possible en javascript:
L' $si la fonction retourne un objet avec le if..then..else..elsif construire, à l'aide de la Condition constructeur.
Une fois que vous appelez Condition.elsif() vous allez créer un autre État de l'objet - essentiellement la création d'une liste, qui peut être parcouru de manière récursive à l'aide de séquences()
Vous pouvez l'utiliser comme:
Cependant, je me rends compte que l'utilisation d'un objet n'est pas une approche purement fonctionnelle. Alors, dans ce cas, vous pouvez renoncer à l'objet, tous ensemble:
Vous pouvez voir que la magie est vraiment dans la séquence() fonction.
Je ne vais pas essayer de répondre à votre question spécifique en javascript. Mais je pense que le point principal est que vous devriez faire une fonction qui va exécuter des fonctions en vertu d'un si..alors l'instruction, puis nid multiples de cette fonction en utilisant la récursivité pour créer un complexe de chaîne logique. Au moins de cette façon vous n'aurez pas à répéter vous-même 😉
Ce code est juste un prototype, donc prenez-le comme une preuve de concept et laissez-moi savoir si vous trouvez des bugs.
b ? x : y