139 votes

Quel est le "Juste" syntaxe signifie en Haskell?

J'ai parcouru l'internet pour une véritable explication de ce que ce mot-clé n'est. Chaque Haskell tutoriel que j'ai regardé commence juste à l'utiliser de façon aléatoire et n'explique jamais ce qu'il fait (et j'ai regardé plusieurs).

Voici une feuille de code de Real World Haskell qui utilise Seulement. Je comprends ce que fait le code, mais je ne comprends pas quel est le but ou la fonction de "Juste".

lend amount balance = let reserve    = 100
                      newBalance = balance - amount
                  in if balance < reserve
                     then Nothing
                     else Just newBalance

De ce que j'ai observé, il est lié à "Peut-être" frappe, mais c'est à peu près tout ce que j'ai réussi à apprendre.

Une bonne explication de ce que signifie Juste serait très apprécié.

238voto

Levi Pearson Points 1856

Il fait juste un type normal constructeur qui arrive à être défini dans le Prélude, qui est la bibliothèque standard, qui est automatiquement importé dans chaque module.

Ce qui est Peut-être, Structurellement

La définition ressemble à quelque chose comme ceci:

data Maybe a = Just a
             | Nothing

Cette déclaration définit un type, Maybe a, ce qui est paramétrée par un type de variable a, ce qui signifie simplement que vous pouvez l'utiliser avec n'importe quel type à la place de a.

La construction et la Destruction

Le type a deux constructeurs, Just a et Nothing. Quand un type a plusieurs constructeurs, cela signifie qu'une valeur de type doit avoir été construit avec juste l'un des constructeurs. Pour ce type, une valeur était construite à l'aide d' Just ou Nothing, il n'y a pas d'autres (sans erreur) possibilités.

Depuis Nothing n'a pas de type de paramètre, lorsqu'il est utilisé en tant que constructeur, c'est le nom d'une valeur constante qui est un membre de type Maybe a pour tous les types a. Mais l' Just constructeur a un paramètre de type, ce qui signifie que lorsqu'il est utilisé en tant que constructeur, il agit comme une fonction de type a de Maybe a, c'est le type a -> Maybe a

Ainsi, les constructeurs d'un type de construire une valeur de ce type; de l'autre côté des choses, c'est quand vous voulez utiliser cette valeur, et c'est là que le pattern matching entre en jeu. Contrairement aux fonctions, les constructeurs peuvent être utilisés dans le modèle des expressions de liaison, et ce est la façon dont vous pouvez faire l'analyse du cas de valeurs qui appartiennent à des types avec plus d'un constructeur.

À l'utilisation de l' Maybe a de la valeur dans un motif, vous devez fournir un modèle pour chaque constructeur, comme suit:

case maybeVal of
    Nothing   -> "There is nothing!"
    Just val  -> "There is a value, and it is " ++ (show val)

Dans ce cas, l'expression, le premier modèle serait de match si la valeur est Nothing, et le second serait de match si la valeur a été construit avec des Just. Si le second correspond, il se lie également le nom d' val pour le paramètre qui a été transmis à l' Just constructeur lorsque la valeur que vous êtes correspondant à contre a été construit.

Ce Qui Signifie Peut-Être

Peut-être vous étiez déjà familier avec la façon dont cela a fonctionné; il n'y a pas vraiment de magie Maybe valeurs, c'est juste normal Haskell Algébrique de Type de Données (ADT). Mais c'est utilisé un peu, parce qu'il fait des "ascenseurs", ou qui s'étend d'un type, comme Integer de votre exemple, dans un nouveau contexte dans lequel il a une valeur supplémentaire (Nothing) qui représente un manque de valeur! Le type de système nécessite que vous vérifiez que la valeur supplémentaire avant de vous laisser à l' Integer qui pourrait être là. Cela empêche un grand nombre de bugs.

De nombreuses langues aujourd'hui gérer ce genre de "non-valeur" valeur via des références NULLES. Tony Hoare, un éminent chercheur en informatique (il a inventé Quicksort et est un de Turing Award winner), propriétaire jusqu'à ce que son "milliards de dollars erreur". Peut-être le type n'est pas le seul moyen de résoudre ce problème, mais il s'est avéré être un moyen efficace de le faire.

Peut-être comme un Foncteur

L'idée de transformer un type à l'autre, telles que les opérations sur le vieux type peut également être transformé à travailler sur le nouveau type est le concept derrière le Haskell type de classe appelé Functor, Maybe a a un utile exemple de.

Functor fournit une méthode appelée fmap, qui associe les fonctions de la gamme de valeurs du type de base (tels que l' Integer) à des fonctions qui vont sur les valeurs de la levée de type (comme Maybe Integer). Une fonction transformée avec fmap de travailler sur un Maybe de la valeur des œuvres comme ceci:

case maybeVal of
  Nothing  -> Nothing         -- there is nothing, so just return Nothing
  Just val -> Just (f val)    -- there is a value, so apply the function to it

Donc, si vous avez un Maybe Integer valeur m_x et Int -> Int fonction f, vous pouvez le faire fmap f m_x appliquer la fonction f directement à l' Maybe Integer sans se soucier de savoir si c'est effectivement une valeur ou non. En fait, vous pouvez appliquer un ensemble de la chaîne de levé Integer -> Integer fonctions d' Maybe Integer valeurs et ont seulement à vous soucier explicitement vérifiant Nothing une fois lorsque vous avez terminé.

Peut-être comme une Monade

Je ne suis pas sûr de savoir comment vous vous serez familiarisé avec le concept de l' Monad encore, mais vous avez au moins utilisée, IO a avant, et la signature de type IO a semble remarquablement similaire Maybe a. Bien qu' IO a pour particularité de ne pas exposer ses constructeurs pour vous, et ne peut donc être "exécuté" par le Haskell système d'exécution, c'est toujours aussi un Functor en plus d'être un Monad. En fait, il y a un sens important dans lequel un Monad est juste un type spécial d' Functor avec quelques fonctionnalités supplémentaires, mais ce n'est pas le lieu d'entrer dans cette.

De toute façon, les Monades comme IO types de carte à de nouveaux types qui représentent "les calculs qui en résultent dans les valeurs" et vous pouvez soulever des fonctions en Monad types via une très fmap-comme la fonction appelée liftM qui transforme une fonction régulière dans un "calcul qui aboutit à la valeur obtenue par l'évaluation de la fonction."

Vous l'avez probablement deviné (si vous avez lu jusqu'ici) Maybe est aussi un Monad. Il représente "calculs qui pourrait ne pas renvoyer une valeur". Tout comme avec l' fmap exemple, cela vous permet de faire tout un tas de calculs sans avoir explicitement vérifier pour les erreurs après chaque étape. Et en fait, la façon dont l' Monad exemple est construit, un calcul sur Maybe valeurs s'arrête dès qu'un Nothing est rencontré, c'est un peu comme un abandon immédiat ou sans valeur de retour dans le milieu d'un calcul.

Vous Auriez Pu Écrire Peut-Être

Comme je l'ai dit avant, il n'y a rien d'inhérent à l' Maybe type qui est cuit dans la syntaxe de la langue ou de l'exécution du système. Si Haskell n'ai pas fourni par défaut, vous pouvez fournir l'ensemble de ses fonctionnalités vous-même! En fait, vous pouvez l'écrire à nouveau vous-même, avec des noms différents, et obtenir la même fonctionnalité.

J'espère que vous comprenez l' Maybe type et ses constructeurs maintenant, mais si il y a encore quelque chose de pas clair, faites le moi savoir!

48voto

Brent Royal-Gordon Points 8044

La plupart des réponses sont très techniques, les explications Just et des amis; j'ai pensé que je pourrais essayer ma main à expliquer ce que c'est.

Beaucoup de langues ont une valeur comme null qui peut être utilisé à la place d'une valeur réelle, au moins pour certains types. Cela a fait beaucoup de gens très en colère et a été largement considéré comme un mauvais coup. Pourtant, il est parfois utile d'avoir une valeur comme null pour indiquer l'absence d'une chose.

Haskell résout ce problème en vous faisant explicitement marquer les endroits où vous pouvez avoir un Nothing (sa version d'un null). En fait, si votre fonction doit normalement retourner le type Foo, il devrait plutôt retourner le type d' Maybe Foo. Si vous voulez indiquer qu'il n'y a pas de valeur de retour Nothing. Si vous voulez retourner une valeur en bar, vous devriez au lieu de regagner Just bar.

Donc, fondamentalement, si vous ne pouvez pas avoir d' Nothing, vous n'avez pas besoin d' Just. Si vous pouvez avoir des Nothing, vous avez besoin d' Just.

Il n'y a rien de magique, Maybe; il est construit sur le Haskell type de système. Cela signifie que vous pouvez utiliser tous les Haskell filtrage des trucs avec elle.

15voto

qaphla Points 3289

Étant donné un type t, une valeur de Just t est une valeur de type tNothing représente un échec pour atteindre une valeur, ou à un cas où le fait d'avoir une valeur serait vide de sens.

Dans votre exemple. avoir un solde négatif n'a pas de sens, et donc, si une telle chose puisse se produire, il est remplacé par Nothing.

Pour un autre exemple, cela pourrait être utilisé dans le titre, la définition d'une division de la fonction qui prend a et b, et les retours Just a/b si b est différente de zéro, et Nothing sinon. Il est souvent utilisé comme cela, comme une alternative pratique pour les exceptions, ou comme votre exemple, de remplacer des valeurs qui n'ont aucun sens.

2voto

Sassa NF Points 3181

Total de la fonction a->b peut trouver une valeur de type b pour chaque valeur de type un.

En Haskell, toutes les fonctions sont total. Dans ce cas particulier de la fonction lend n'est pas totale - elle n'est pas définie pour le cas lorsque le solde est à moins de réserve (même si, à mon goût, il serait plus logique de ne pas permettre newBalance à moins de réserve - comme, vous pouvez emprunter de 101 à partir d'un solde de 100).

D'autres modèles qui traitent de la totale non-fonctions:

  • lancer des exceptions lors de la vérification de la valeur d'entrée ne correspond pas à la plage
  • de retour d'une valeur particulière (type primitif): choix favori est une valeur négative pour les fonctions entières qui sont destinés à retourner nombres Naturels (par exemple, Chaîne.indexOf - lorsqu'une sous-chaîne n'est pas trouvée, le retour de l'indice est généralement conçu pour être négatif)
  • de retour d'une valeur particulière (pointeur): la valeur NULL ou de certaines de ces
  • silencieusement retourner sans rien faire: par exemple, lend pourrait être écrit pour revenir ancien solde, si la condition pour le prêt n'est pas remplie
  • de retour d'une valeur particulière: Rien (ou Gauche habillage de l'erreur description de l'objet)

Celles-ci sont nécessaires limites de la conception dans des langues qui ne peut pas appliquer la totalité des fonctions (par exemple, Agda peut, mais cela mène à d'autres complications, comme devenir turing-incomplet).

Le problème avec le retour de la valeur particulière, ou de lever des exceptions, c'est qu'il est facile pour l'appelant d'omettre la manipulation d'une telle possibilité, par erreur.

Le problème avec silencieusement jeter un échec est également évident - vous de limiter ce que l'appelant peut faire avec la fonction. Par exemple, si lend retourné ancien solde, l'appelant a aucun moyen de savoir si l'équilibre a changé. Il peut ou peut ne pas être un problème, en fonction de l'usage prévu.

Haskell solution forces de l'appelant d'une fonction partielle de traiter avec le type Maybe aou Either error a en raison de la fonction de type de retour.

De cette façon, lend tel qu'il est défini, est une fonction qui n'est pas toujours calculer new balance - pour certaines circonstances, new balance n'est pas défini. Nous signalons cette circonstance à l'appelant par retourner la valeur spéciale Rien, ou en les enveloppant le nouvel équilibre Juste. L'appelant a maintenant la liberté de choisir: soit de gérer la défaillance de prêter d'une manière particulière, ou de l'ignorer et utiliser l'ancien équilibre - par exemple, maybe oldBalance id $ lend amount oldBalance.

-1voto

wit Points 1359

La fonction if (cond :: Bool) then (ifTrue :: a) else (ifFalse :: a) doivent avoir le même type d' ifTrue et ifFalse.

Donc, lorsque nous écrivons, then Nothing, il faut utiliser Maybe a type en else f

if balance < reserve
       then (Nothing :: Maybe nb)         -- same type
       else (Just newBalance :: Maybe nb) -- same type

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X