Qu'est-ce qu'une «représentation levée»?

12

Je viens de parcourir ce terme ici:

http://www.codemesh.io/codemesh2014/viktor-klang

"Nous allons démontrer l'API Flow — une représentation levée — ainsi qu'un moyen enfichable de transformer la représentation levée en représentation d'exécution — la matérialisation du flux.”

La recherche sur Google n'a pas beaucoup aidé.

Tanière
la source
lecture recommandée: Discutez de ce $ {blog}
gnat
11
@gnat il semble qu'il n'ait pas inventé ce terme, il ne ressemble pas à une opinion, il est peu probable qu'il provoque une discussion et mon instinct est que ça ne va pas être trop large (même si ça ressemble à des maths).
Den
2
Je discute de la signification de "levé" dans le contexte de C # ici: blogs.msdn.com/b/ericlippert/archive/2007/06/27/… - probablement les développeurs Scala utilisent le terme dans un analogue, mais plus mode générale.
Eric Lippert

Réponses:

22

Je ne connais pas l'API Flow.

Le terme «levage» vient de la théorie des catégories. Dans les langages de programmation tels que Haskell ou Scala, une liftfonction prend une fonction A => B, et effectue en quelque sorte la magie de sorte que la fonction levée F[A] => F[B]peut être appliquée à un foncteur ou une monade F[A].

Un exemple concret utilisant le Seqconteneur de Scala : Supposons que nous ayons une fonction def double(x: Int): Int = 2 * xet une séquence val xs = Seq(1, 2, 3). Nous ne pouvons pas en double(xs)raison de types incompatibles. Mais si nous obtenons un val doubleSeq = liftToSeq(double), nous pouvons le faire doubleSeq(xs), ce qui correspond à Seq(2, 4, 6). Ici, liftToSeqpeut être implémenté comme

def liftToSeq[A, B](f: A => B): (Seq[A] => Seq[B]) =
  (seq: Seq[A]) => seq.map(f)

Le Seq(…)constructeur peut également être vu comme une opération de levage, qui soulève les valeurs 1, 2, 3dans une Seqinstance, nous permettant ainsi d'utiliser des abstractions de liste pour ces valeurs.

Les monades nous permettent d'encapsuler le fonctionnement interne d'un certain type en offrant une interface étanche mais composable. L'utilisation d'une représentation levée peut faciliter la réflexion sur un calcul. L'utilisation de telles abstractions signifie également que nous perdons la connaissance des spécificités abstraites, mais celles-ci sont nécessaires pour fournir une implémentation efficace sous le capot (trouver une représentation d'exécution appropriée).

amon
la source
4
Voilà une bonne description du «levage» mathématique. Nous devrions également inclure une référence à la description plus formelle de la levée de Wikipedia .
Scott Whitlock, le
3
Un exemple peut-être plus clair de "levage" consiste à passer aux types annulables (ou "facultatifs" ou "peut-être"). Par exemple, supposons que vous ayez +défini un opérateur tel que int + int --> int. L'opérateur levé à nullable int? + int? --> int?a la sémantique "si l'un des opérandes est nul alors la réponse est nulle, sinon utilisez l'opérateur non levé sur les valeurs".
Eric Lippert
@ScottWhitlock Vous soulevez-vous même?
helrich
1
@Frank J'ai lu l'article Wikipedia avant d'écrire ma réponse et je ne l'ai pas compris non plus. Au lieu de cela, j'ai trouvé le wiki Haskell sur le levage plus accessible. Notez que nous n'avons pas vraiment quatre types. Nous avons quatre types concrets, mais seulement trois variables de type: deux types Aet B, et un foncteur Fqui est un constructeur de type.
amon
1
Je ne suis pas trop profondément dans tout cela, mais si Fc'est un constructeur de type, alors F[A]c'est l'un de ses types construits. Alors pourquoi est-ce mal de parler de ces quatre types? (deux types et un constructeur de type seraient tout aussi bien, bien sûr)
Frank
6

Le terme lever peut bien entendu avoir différentes significations selon le contexte.

Dans la programmation générique, il décrit le processus d'abstraction au niveau supérieur suivant. Par exemple, vous pouvez avoir deux morceaux de code, un type avec intet l'autre avec float. Soulever ce code signifierait quelque chose comme un modèle de la méthode avec un type générique Tqui fonctionne pour les deux, intet float.

J'ai trouvé que cette utilisation du terme était une bonne directive intuitive pour ce que signifie le levage . La seule différence qui semble exister entre les différents contextes est ce qu'est réellement cette abstraction supérieure.

En particulier, Viktor est connu dans le contexte de la programmation fonctionnelle, et dans ce contexte, vous pouvez y trouver des interprétations visuellement différentes de la levée . Un exemple, est de soulever des valeurs dans un foncteur, ou de lever des fonctions pour travailler sur des valeurs monadiques (c'est-à-dire Haskell liftM2).

Un exemple très concret de "représentation levée" pourrait alors ex. être un List(1)ou un Some(1).

Franc
la source
4

Ces types de concepts sont généralement plus faciles à comprendre avec un exemple concret. Considérez l'extrait suivant de cet exemple d'API Flow :

Flow(text.split("\\s").toVector).
      // transform
      map(line => line.toUpperCase).
      // print to console (can also use ``foreach(println)``)
      foreach(transformedLine => println(transformedLine)).
      onComplete(FlowMaterializer(MaterializerSettings())) {
        case Success(_) => system.shutdown()
        case Failure(e) =>
          println("Failure: " + e.getMessage)
          system.shutdown()
      }

Cela prend le code suivant:

text.split("\\s").toVector.
      map(line => line.toUpperCase).
      foreach(println)

et le "met" dans un Flowcontexte. Cela vous permet d'utiliser la même syntaxe que vous connaissez pour spécifier votre algorithme, mais en arrière map-plan, cela se fait en parallèle sur plusieurs processeurs ou même sur des machines, puis le foreach(println)collecte de manière transparente cette sortie vers un processeur pour l'impression.

Il s'agit d'un terme générique qui peut faire référence à l'habillage de tout contexte autour de tout type. Un autre exemple plus familier est celui qui mapprend une fonction qui fonctionne sur un seul élément et la "lève" dans le nouveau contexte de travail sur une collection de ces éléments. Le levage est omniprésent dans la programmation fonctionnelle et l'une des principales raisons pour lesquelles il est tellement plus facile de réutiliser le code fonctionnel.

Karl Bielefeldt
la source