Introduction aux Expressions de calcul de F#

À propos de l'auteur :

MVP Cet article est fourni par le MVP Eriawan Kusumawardhono. Microsoft est te remercie que MVP proactive de partager leur expérience professionnelle avec d’autres utilisateurs. L’article est comptabilisé ultérieurement sur le site de Web de MVP ou un blog .

Vue d’ensemble

F# est le langage de programmation de paradigme de multiples. Il contient un langage de programmation fonctionnel et orienté objet langage de programmation, bien qu’il est souligné plus en tant que langage de programmation fonctionnel et également le code fonctionne dans le style. Une fonctionnalités qui existent souvent dans la programmation fonctionnelle est mise en séquence et composition de fonction, et il est largement utilisé pour implémenter Monad.

F# a l’expression de calcul dans les formulaires de flux de contrôle et des liaisons pour composer et combiner des opérations, fonctions. Expression de calcul de F# est F# fonctionnalité fonctionnelle pour implémenter Monad. Expression de calcul dans monad peut donc servir à gérer les calculs de l’effet secondaire, pas seulement les flux de contrôle et les données.


Expressions de calcul intégré dans F#

F# a déjà implémenté calcul intégré F# langage d’expression : la séquence d’opérations, le seq et le flux de travail asynchrone de async. Seq utilise le rendement et le rendement ! Pour définir la séquence d’opérations et il nous donne flux de contrôle dans un formulaire d’évaluation différée ou différée. Flux de travail asynchrone est très utile et nous offre l’easiness à des opérations asynchrones de code utilisant les mots-clés async .

Mise en œuvre de vos propres expressions de calcul

Mise en œuvre d’expression de calcul dans F# a de nombreuses façons, mais la méthode la plus courante à l’aide de cette syntaxe est mise en œuvre du modèle du générateur :

Générateur-nom {expression}

Ce nom de générateur est un identificateur pour une instance d’un type spécial appelé le type de générateur ou d’une classe. Un autre décrire une classe de générateur consiste à dire qu’il vous permet de personnaliser le fonctionnement de plusieurs F# constructions, telles que les boucles et les liaisons. Ce sont les méthodes et les signatures des méthodes à l’intérieur d’un générateur :

list of methods for builder

Comme nous pouvons observer dans le tableau ci-dessus, la plupart des méthodes retournent M < ' t > comme type de retour. Et cette construction est également utilisée dans intégrés Async < ' t > et Seq < ' t > dans F#.

MSDN Library de F# d’expression de calcul placer plus d’informations :

«Les signatures de ces méthodes leur permettant d’être combinées et imbriquées les uns avec les autres, afin que l’objet de flux de travail retourné d’une construction qui peut être passé à la suivante.»
Cela implique également que les types retournée doit être la même pour combiner une construction avec un autre, comme nous le constatons souvent dans la combinaison d’opérations de séquence et flux de travail asynchrone dans F#.

Exemple d’implémentation d’expressions de calcul

Nous pouvons créer de nombreux types de monades qui sont à l’aide de F#. Les exemples ci-dessous fournira des exemples de scénarios de simple Monad peut-être à gérer les complexités d’accepter des entrées pour exploiter les expressions de calculs pour implémenter un langage spécifique à un domaine simple.

Nous créons maintenant peut-être monad. C’est le scénario d’arrière-plan : nous souhaitons écrire une fonction qui demande à l’utilisateur de 3 entrées entier compris entre 0 et 100 (inclus). Mais s’il existe des entrées non valides, tels que les entiers non numérique ou non, l’exécution de la fonction doit être abandonnée.

Nous pouvons écrire l’intention d’origine en F# comme suit :

let addThreeNumbers() =    let getNum msg =
printf "%s" msg
match System.Int32.TryParse(System.Console.ReadLine()) with
| (true, n) when n >= 0 && n <= 100 -> Some(n)
| _ -> None

match getNum "#1: " with
| Some(x) ->
match getNum "#2: " with
| Some(y) ->
match getNum "#3: " with
| Some(z) -> Some(x + y + z)
| None -> None
| None -> None
| None -> None
Le code a bien fait son travail, mais il semble répétitives dans certaines fonctions et par conséquent très redondantes. À l’aide d’expressions de calcul, nous pouvons réécrire le code ci-dessus comme suit :

let addThreeNumbers() =    let bind(input, rest) =
match System.Int32.TryParse(input()) with
| (true, n) when n >= 0 && n <= 100 -> rest(n)
| _ -> None

let createMsg msg = fun () -> printf "%s" msg; System.Console.ReadLine()

bind(createMsg "#1: ", fun x ->
bind(createMsg "#2: ", fun y ->
bind(createMsg "#3: ", fun z -> Some(x + y + z) ) ) )

La fonction se présente désormais plus simple, et il utilise plusieurs opérations de liaison pour la liaison de createMsg avec les définitions de liaison après la signature de la fonction. Il gère également des effets secondaires normalement.

Un autre Monad commune est monad du lecteur. Monad de ce lecteur est très utile, lecture de valeurs à partir de l’environnement et parfois exécutent des sous-calculs dans un environnement de modification (avec des liaisons nouvelles ou occultation, par exemple), mais ils ne nécessitent pas la généralité complète de monad de l’état.

Il s’agit d’un exemple de code de lecteur Monad :

    open System    type Reader<'r,'a> = 'r -> 'a

let bind k m = fun r -> (k (m r)) r

/// The reader monad.
/// This monad comes from Matthew Podwysocki's http://codebetter.com/blogs/matthew.podwysocki/archive/2010/01/07/much-ado-about-monads-reader-edition.aspx.
type ReaderBuilder() =
member this.Return(a) : Reader<'r,'a> = fun _ -> a
member this.ReturnFrom(a:Reader<'r,'a>) = a
member this.Bind(m:Reader<'r,'a>, k:'a -> Reader<'r,'b>) : Reader<'r,'b> = bind k m
member this.Zero() = this.Return ()
member this.Combine(r1, r2) = this.Bind(r1, fun () -> r2)
member this.TryWith(m:Reader<'r,'a>, h:exn -> Reader<'r,'a>) : Reader<'r,'a> =
fun env -> try m env
with e -> (h e) env
member this.TryFinally(m:Reader<'r,'a>, compensation) : Reader<'r,'a> =
fun env -> try m env
finally compensation()
member this.Using(res:#IDisposable, body) =
this.TryFinally(body res, (fun () -> match res with null -> () | disp -> disp.Dispose()))
member this.Delay(f) = this.Bind(this.Return (), f)
member this.While(guard, m) =
if not(guard()) then this.Zero() else
this.Bind(m, (fun () -> this.While(guard, m)))
member this.For(sequence:seq<_>, body) =
this.Using(sequence.GetEnumerator(),
(fun enum -> this.While(enum.MoveNext, this.Delay(fun () -> body enum.Current))))
Il s’agit de l’exemple d’utilisation de ce générateur de lecteur :

    let reader = new ReaderBuilder()    
let ask : Reader<'r,'r> = id
let asks f = reader {
let! r = ask
return (f r) }
Ces utilisations builder peuvent également servir à composer l’interface utilisateur. Les modèles de cette composition peuvent souvent être consultées comme un langage spécifique à un domaine de manière contrôlée dans le Générateur de.

L’article de code de lecteur monad a été extraite de blog de Matthew Podwysocki de mise en œuvre de Monad du lecteur : http://codebetter.com/matthewpodwysocki/2010/01/07/much-ado-about-monads-reader-edition/

Le générateur peut également servir à composer l’Interface utilisateur (UI). Ceci est le générateur dans le style de mise en œuvre orientée objet à l’aide de WPF :

#r "WindowsBase.dll"#r "PresentationCore.dll"
#r "PresentationFramework.dll"
#r "System.Xaml"
#endif

open System
open System.Windows
open System.Windows.Controls

[<AbstractClass>]
type IComposableControl<'a when 'a :> FrameworkElement> () =
abstract Control : 'a
abstract Bind : FrameworkElement * (FrameworkElement -> 'a) -> 'a
abstract Bind : IComposableControl<'b> * (FrameworkElement -> 'a) -> 'a
member this.Return (e: unit) = this.Control
member this.Zero () = this.Control

type WindowBuilder() =
inherit IComposableControl<Window>()
let win = Window(Topmost=true)
override this.Control = win
override this.Bind(c: FrameworkElement, body: FrameworkElement -> Window) : Window =
win.Content <- c
body c
override this.Bind(c: IComposableControl<'b>, body: FrameworkElement -> Window) : Window =
win.Content <- c.Control
body c.Control

type PanelBuilder(panel: Panel) =
inherit IComposableControl()
override this.Control = panel
override this.Bind(c: FrameworkElement, body: FrameworkElement -> Panel) : Panel=
panel.Children.Add(c) |> ignore
body c
override this.Bind(c: IComposableControl<'b>, body: FrameworkElement -> Panel) : Panel=
panel.Children.Add(c.Control) |> ignore
body c.Control


Et c’est l’utilisation de générateurs de ci-dessus :

 let win =
WindowBuilder()
{ let! panel =
PanelBuilder(StackPanel())
{ let! btn1 = Button(Content = "Hello")
let! btn2 = Button(Content = "World")
return () }
return () }

win.Show() // Pops up the window in FSI.

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run() |> ignore
#endif

Notez la mise en oeuvre de IComposableControl ; Il possède une déclaration abstraite des méthodes de liaison. Les implémentations concrètes réelles, le WindowBuilder et le PanelBuilder mettre en œuvre Bind parfaitement avec les flux de type.

Les générateurs de l’interface utilisateur ci-dessus a été extraite de l’article de Adam Granicz : http://www.devx.com/enterprise/Article/40481

Plus d'informations

Pour plus d’informations, visitez le site :
  1. En 2010 de Visual Studio : http://msdn.microsoft.com/en-us/library/dd233182(v=vs.100).aspx
  2. En 2012 de Visual Studio : http://msdn.microsoft.com/en-us/library/dd233182.aspx


Exclusion de contenu communautaire Solutions

MICROSOFT CORPORATION ET/OU SES FOURNISSEURS RESPECTIFS NE FONT AUCUNE DÉCLARATION SUR LA PERTINENCE, DE FIABILITÉ OU L’EXACTITUDE DES INFORMATIONS ET DES ÉLÉMENTS GRAPHIQUES ASSOCIÉS CONTENUS DANS LE PRÉSENT DOCUMENT. TOUTES CES INFORMATIONS ET ÉLÉMENTS GRAPHIQUES ASSOCIÉS SONT FOURNIS « EN L’ÉTAT » SANS GARANTIE D’AUCUNE SORTE. MICROSOFT ET/OU SES FOURNISSEURS RESPECTIFS EXCLUENT TOUTES LES GARANTIES ET CONDITIONS RELATIVES À CES INFORMATIONS ET LES GRAPHIQUES ASSOCIÉS, NOTAMMENT TOUTE GARANTIE IMPLICITE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER, LOIS ET D’ABSENCE DE CONTREFAÇON. VOUS RECONNAISSEZ SPÉCIFIQUEMENT QU’EN AUCUN CAS MICROSOFT ET/OU SES FOURNISSEURS EST RESPONSABLES POUR DES DOMMAGES DIRECTS, INDIRECTS, PUNITIFS, OU ACCESSOIRES, SPÉCIALES, NI LES DOMMAGES QUELCONQUES Y COMPRIS, SANS LIMITATION, LES DOMMAGES POUR PERTE D’UTILISATION, DE DONNÉES OU DE BÉNÉFICES, DÉCOULANT D’OU DANS N’IMPORTE QUEL LIÉS À L’UTILISATION D’OU DE L’INCAPACITÉ À UTILISER LES INFORMATIONS ET LES ÉLÉMENTS GRAPHIQUES ASSOCIÉS CONTENUS DANS LE PRÉSENT DOCUMENT , BASÉ SUR LE CONTRAT, RESPONSABILITÉ DÉLICTUELLE, NÉGLIGENCE, RESPONSABILITÉ STRICTE OU AUTREMENT, MÊME SI MICROSOFT OU L'UN DE SES FOURNISSEURS A ÉTÉ AVERTI DE L'ÉVENTUALITÉ DE DOMMAGES.
Propriétés

ID d'article : 2832367 - Dernière mise à jour : 26 janv. 2017 - Révision : 1

Microsoft Visual Studio Express 2012 for Web, Microsoft Visual Studio Premium 2012, Microsoft Visual Studio Professional 2012, Microsoft Visual Studio Ultimate 2012

Commentaires