स्काला और LWJGL का उपयोग करके एक सरलीकृत खेल के लिए कार्यात्मक प्रोग्रामिंग दृष्टिकोण


11

मैं, जावा अनिवार्य प्रोग्रामर, यह समझना चाहूंगा कि कार्यात्मक प्रोग्रामिंग डिजाइन सिद्धांतों (विशेष रूप से संदर्भीय पारदर्शिता) के आधार पर अंतरिक्ष आक्रमणकारियों का एक सरल संस्करण कैसे उत्पन्न किया जाए। हालांकि, हर बार जब मैं एक डिजाइन के बारे में सोचने की कोशिश करता हूं, तो मैं अत्यधिक परिवर्तनशीलता के नैतिकता में खो जाता हूं, वही परिवर्तनशीलता जो कार्यात्मक प्रोग्रामिंग शुद्धतावादियों से दूर हो जाती है।

कार्यात्मक प्रोग्रामिंग सीखने के प्रयास के रूप में, मैंने LWJGL का उपयोग करते हुए स्काला में एक बहुत ही सरल 2D इंटरएक्टिव गेम, स्पेस इनवेडर (बहुवचन की कमी पर ध्यान दें) बनाने का प्रयास करने का निर्णय लिया । यहाँ बुनियादी खेल के लिए आवश्यकताएं हैं:

  1. स्क्रीन के नीचे स्थित उपयोगकर्ता जहाज क्रमशः "A" और "D" कुंजी द्वारा बाएँ और दाएँ ले जाया गया

  2. यूजर शिप बुलेट को .5 सेकंड के शॉट्स के बीच न्यूनतम ठहराव के साथ स्पेस बार द्वारा सीधे सक्रिय किया गया

  3. विदेशी जहाज गोली सीधे शॉट के बीच .5 से 1.5 सेकंड के एक यादृच्छिक समय से सक्रिय नीचे निकाल दिया

मूल खेल से जानबूझकर छोड़ी गई चीजें स्क्रीन के शीर्ष पर WxH एलियंस, नीच रक्षा बाधाओं X3, उच्च गति तश्तरी जहाज हैं।

ठीक है, अब वास्तविक समस्या डोमेन पर। मेरे लिए, सभी निर्धारक भाग स्पष्ट हैं। यह गैर-नियतात्मक भाग है जो यह सोचने की मेरी क्षमता को अवरुद्ध करता है कि कैसे दृष्टिकोण करना है। नियतात्मक भाग बुलेट के प्रक्षेपवक्र हैं एक बार जब वे मौजूद होते हैं, तो एलियन और विस्फोट की निरंतर गति खिलाड़ी के जहाज या एलियन के दोनों (या दोनों) पर एक हिट के कारण होती है। गैर-नियतात्मक भागों (मेरे लिए) उपयोगकर्ता इनपुट की धारा को संभाल रहे हैं, विदेशी बुलेट फायरिंग का निर्धारण करने के लिए एक यादृच्छिक मूल्य प्राप्त करने और आउटपुट (ग्राफिक्स और ध्वनि दोनों) को संभाल रहे हैं।

मैं वर्षों से इस प्रकार के बहुत सारे खेल विकास कर सकता हूं (और किया है)। हालाँकि, यह सभी अनिवार्य प्रतिमान से था। और LWJGL भी अंतरिक्ष आक्रमणकारियों का एक बहुत ही सरल जावा संस्करण प्रदान करता है (जिनमें से मैंने स्काला का उपयोग जावा-बिना-अर्धविराम के रूप में स्काला में करना शुरू किया था)।

यहां कुछ लिंक दिए गए हैं, जो इस क्षेत्र के चारों ओर बात करते हैं, जिनमें से कोई भी उन विचारों से सीधे तौर पर नहीं निपटता है जो जावा / इंपीरियल प्रोग्रामिंग से आने वाले व्यक्ति को समझ में आएंगे:

  1. विशुद्ध रूप से कार्यात्मक रेट्रो ड्रैगन, भाग 1 जेम्स हेग द्वारा

  2. इसी तरह की ढेर अतिप्रवाह पोस्ट

  3. क्लोजर / लिस्प गेम्स

  4. स्टैक ओवरफ्लो पर हास्केल गेम्स

  5. यंपा (हास्केल में) कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग

ऐसा प्रतीत होता है कि क्लोजर / लिस्प और हास्केल गेम (स्रोत के साथ) में कुछ विचार हैं। दुर्भाग्य से, मैं कोड को मानसिक मॉडल में पढ़ने / व्याख्या करने में सक्षम नहीं हूं जो मेरे सरल जावा अनिवार्य मस्तिष्क के लिए कोई मतलब नहीं है।

मैं एफपी द्वारा की पेशकश की संभावनाओं से बहुत उत्साहित हूं, मैं बस बहु-थ्रेडेड स्केलेबिलिटी क्षमताओं का स्वाद ले सकता हूं। मुझे लगता है कि अगर अंतरिक्ष आक्रमणकारी के लिए समय + घटना + यादृच्छिकता मॉडल के रूप में सरल रूप में कुछ को कैसे उतारा जा सकता है, तो यह निर्धारित गणितीय सिद्धांत के अनुसार महसूस किए बिना एक उचित रूप से डिज़ाइन किए गए सिस्टम में नियतात्मक और गैर-नियतात्मक भागों को अलग करना है। ; यानी यमपा, मैं सेट हो जाता। यदि सिद्धांत के स्तर को सीखना यम्पा को लगता है कि सफलतापूर्वक सरल गेम उत्पन्न करने के लिए आवश्यक है, तो सभी आवश्यक प्रशिक्षण और वैचारिक ढांचे को प्राप्त करने का ओवरहेड एफपी के लाभों की मेरी समझ को कम कर देगा (कम से कम इस अति-सरल सीखने के प्रयोग के लिए) )।

किसी भी प्रतिक्रिया, प्रस्तावित मॉडल, समस्या डोमेन (जेम्स हेग द्वारा कवर किए गए सामान्यों की तुलना में अधिक विशिष्ट) के दृष्टिकोण के तरीकों की बहुत सराहना की जाएगी।


1
मैंने आपके ब्लॉग के बारे में प्रश्न से भाग हटा दिया है, क्योंकि यह स्वयं प्रश्न के लिए आवश्यक नहीं था। जब आप इसे लिखने के लिए आते हैं, तो एक अनुवर्ती लेख के लिंक को शामिल करने के लिए स्वतंत्र महसूस करें।
यनीस

@ यानिस - समझ गया। Tyvm!
अव्यवस्थित 3

आपने स्काला के लिए कहा, यही कारण है कि यह केवल एक टिप्पणी है। क्लोजर की गुफाओं को एक roguelike FP स्टाइल को लागू करने के तरीके पर एक प्रबंधनीय पढ़ा जाता है। यह दुनिया का एक स्नैपशॉट लौटाकर राज्य को संभालता है जिसे लेखक तब परीक्षण कर सकता है। यह बहुत मजेदार है। हो सकता है कि आप पोस्टों के माध्यम से ब्राउज़ कर सकते हैं और देख सकते हैं कि क्या उसके कार्यान्वयन के किसी भी हिस्से को आसानी से स्लैला में स्थानांतरित किया जा सकता है
IAE

जवाबों:


5

अंतरिक्ष आक्रमणकारियों का एक मुहावरेदार स्काला / LWJGL कार्यान्वयन एक हास्केल / ओपनजीएल कार्यान्वयन की तरह नहीं लगेगा। हास्केल कार्यान्वयन लिखना मेरी राय में एक बेहतर अभ्यास हो सकता है। लेकिन अगर आप स्काला के साथ रहना चाहते हैं, तो यहां कुछ विचार हैं कि इसे कार्यात्मक शैली में कैसे लिखा जाए।

केवल अपरिवर्तनीय वस्तुओं का उपयोग करने का प्रयास करें। आपके पास एक Gameवस्तु हो सकती है जो एक Player, Set[Invader]( एक का उपयोग करना सुनिश्चित करें immutable.Set), आदि दे ( Playerएक update(state: Game): Playerभी ले सकता है depressedKeys: Set[Int], आदि), और अन्य वर्गों को समान तरीके दें।

यादृच्छिकता के लिए, scala.util.Randomहास्केल की तरह अपरिवर्तनीय नहीं है System.Random, लेकिन आप अपने खुद के इम्यूमेटेबल जनरेटर बना सकते हैं। यह एक अक्षम है लेकिन यह विचार को प्रदर्शित करता है।

case class ImmutablePRNG(val seed: Long) extends Immutable {
    lazy val nextLong: (Long, ImmutableRNG) =
        (seed, ImmutablePRNG(new Random(seed).nextLong()))
    ...
}

कीबोर्ड / माउस इनपुट और रेंडरिंग के लिए, अशुद्ध कार्यों को कॉल करने का कोई तरीका नहीं है। वे हास्केल में भी अपवित्र हैं, वे सिर्फ IOआदि में लिप्त हैं ताकि आपके वास्तविक फ़ंक्शन ऑब्जेक्ट तकनीकी रूप से शुद्ध हों (वे खुद को राज्य नहीं पढ़ते या लिखते हैं, वे दिनचर्या का वर्णन करते हैं जो करते हैं, और रनटाइम सिस्टम उन दिनचर्या को निष्पादित करता है) ।

जिस प्रकार आपका अपरिवर्तनीय वस्तुओं में आई / ओ कोड डाल नहीं Game, Playerऔर Invader। आप Playerएक renderविधि दे सकते हैं , लेकिन यह दिखना चाहिए

render(state: Game, buffer: Image): Image

दुर्भाग्य से यह एलडब्ल्यूजेजीएल के साथ अच्छी तरह से फिट नहीं है क्योंकि यह इतना राज्य-आधारित है, लेकिन आप इसके शीर्ष पर अपने खुद के अमूर्त का निर्माण कर सकते हैं। आपके पास एक ImmutableCanvasवर्ग हो सकता है जो एक AWT रखता है Canvas, और इसके blit(और अन्य तरीके) अंतर्निहित क्लोन कर सकता है Canvas, इसे पास कर सकता है Display.setParent, फिर रेंडरिंग कर सकता है और नया Canvas(आपके अपरिवर्तनीय आवरण में) वापस कर सकता है।


अपडेट : यहां कुछ जावा कोड दिखाया गया है कि मैं इस बारे में कैसे जाऊंगा। (मैंने स्कैला में लगभग एक ही कोड लिखा होगा, सिवाय इसके कि एक अपरिवर्तनीय सेट बिल्ट-इन है और प्रत्येक के लिए कुछ छोरों को नक्शे या सिलवटों से बदला जा सकता है।) मैंने एक खिलाड़ी बनाया जो चारों ओर घूमता है और गोलियां चलाता है, लेकिन मैं। कोड लंबे समय से पहले से ही हो रहा था क्योंकि दुश्मनों को नहीं जोड़ा। मैंने बस सब कुछ कॉपी-ऑन-राइट के बारे में बनाया - मुझे लगता है कि यह सबसे महत्वपूर्ण अवधारणा है।

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

import static java.awt.event.KeyEvent.*;

// An immutable wrapper around a Set. Doesn't implement Set or Collection
// because that would require quite a bit of code.
class ImmutableSet<T> implements Iterable<T> {
  final Set<T> backingSet;

  // Construct an empty set.
  ImmutableSet() {
    backingSet = new HashSet<T>();
  }

  // Copy constructor.
  ImmutableSet(ImmutableSet<T> src) {
    backingSet = new HashSet<T>(src.backingSet);
  }

  // Return a new set with an element added.
  ImmutableSet<T> plus(T elem) {
    ImmutableSet<T> copy = new ImmutableSet<T>(this);
    copy.backingSet.add(elem);
    return copy;
  }

  // Return a new set with an element removed.
  ImmutableSet<T> minus(T elem) {
    ImmutableSet<T> copy = new ImmutableSet<T>(this);
    copy.backingSet.remove(elem);
    return copy;
  }

  boolean contains(T elem) {
    return backingSet.contains(elem);
  }

  @Override public Iterator<T> iterator() {
    return backingSet.iterator();
  }
}

// An immutable, copy-on-write wrapper around BufferedImage.
class ImmutableImage {
  final BufferedImage backingImage;

  // Construct a blank image.
  ImmutableImage(int w, int h) {
    backingImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  }

  // Copy constructor.
  ImmutableImage(ImmutableImage src) {
    backingImage = new BufferedImage(
        src.backingImage.getColorModel(),
        src.backingImage.copyData(null),
        false, null);
  }

  // Clear the image.
  ImmutableImage clear(Color c) {
    ImmutableImage copy = new ImmutableImage(this);
    Graphics g = copy.backingImage.getGraphics();
    g.setColor(c);
    g.fillRect(0, 0, backingImage.getWidth(), backingImage.getHeight());
    return copy;
  }

  // Draw a filled circle.
  ImmutableImage fillCircle(int x, int y, int r, Color c) {
    ImmutableImage copy = new ImmutableImage(this);
    Graphics g = copy.backingImage.getGraphics();
    g.setColor(c);
    g.fillOval(x - r, y - r, r * 2, r * 2);
    return copy;
  }
}

// An immutable, copy-on-write object describing the player.
class Player {
  final int x, y;
  final int ticksUntilFire;

  Player(int x, int y, int ticksUntilFire) {
    this.x = x;
    this.y = y;
    this.ticksUntilFire = ticksUntilFire;
  }

  // Construct a player at the starting position, ready to fire.
  Player() {
    this(SpaceInvaders.W / 2, SpaceInvaders.H - 50, 0);
  }

  // Update the game state (repeatedly called for each game tick).
  GameState update(GameState currentState) {
    // Update the player's position based on which keys are down.
    int newX = x;
    if (currentState.keyboard.isDown(VK_LEFT) || currentState.keyboard.isDown(VK_A))
      newX -= 2;
    if (currentState.keyboard.isDown(VK_RIGHT) || currentState.keyboard.isDown(VK_D))
      newX += 2;

    // Update the time until the player can fire.
    int newTicksUntilFire = ticksUntilFire;
    if (newTicksUntilFire > 0)
      --newTicksUntilFire;

    // Replace the old player with an updated player.
    Player newPlayer = new Player(newX, y, newTicksUntilFire);
    return currentState.setPlayer(newPlayer);
  }

  // Update the game state in response to a key press.
  GameState keyPressed(GameState currentState, int key) {
    if (key == VK_SPACE && ticksUntilFire == 0) {
      // Fire a bullet.
      Bullet b = new Bullet(x, y);
      ImmutableSet<Bullet> newBullets = currentState.bullets.plus(b);
      currentState = currentState.setBullets(newBullets);

      // Make the player wait 25 ticks before firing again.
      currentState = currentState.setPlayer(new Player(x, y, 25));
    }
    return currentState;
  }

  ImmutableImage render(ImmutableImage img) {
    return img.fillCircle(x, y, 20, Color.RED);
  }
}

// An immutable, copy-on-write object describing a bullet.
class Bullet {
  final int x, y;
  static final int radius = 5;

  Bullet(int x, int y) {
    this.x = x;
    this.y = y;
  }

  // Update the game state (repeatedly called for each game tick).
  GameState update(GameState currentState) {
    ImmutableSet<Bullet> bullets = currentState.bullets;
    bullets = bullets.minus(this);
    if (y + radius >= 0)
      // Add a copy of the bullet which has moved up the screen slightly.
      bullets = bullets.plus(new Bullet(x, y - 5));
    return currentState.setBullets(bullets);
  }

  ImmutableImage render(ImmutableImage img) {
    return img.fillCircle(x, y, radius, Color.BLACK);
  }
}

// An immutable, copy-on-write snapshot of the keyboard state at some time.
class KeyboardState {
  final ImmutableSet<Integer> depressedKeys;

  KeyboardState(ImmutableSet<Integer> depressedKeys) {
    this.depressedKeys = depressedKeys;
  }

  KeyboardState() {
    this(new ImmutableSet<Integer>());
  }

  GameState keyPressed(GameState currentState, int key) {
    return currentState.setKeyboard(new KeyboardState(depressedKeys.plus(key)));
  }

  GameState keyReleased(GameState currentState, int key) {
    return currentState.setKeyboard(new KeyboardState(depressedKeys.minus(key)));
  }

  boolean isDown(int key) {
    return depressedKeys.contains(key);
  }
}

// An immutable, copy-on-write description of the entire game state.
class GameState {
  final Player player;
  final ImmutableSet<Bullet> bullets;
  final KeyboardState keyboard;

  GameState(Player player, ImmutableSet<Bullet> bullets, KeyboardState keyboard) {
    this.player = player;
    this.bullets = bullets;
    this.keyboard = keyboard;
  }

  GameState() {
    this(new Player(), new ImmutableSet<Bullet>(), new KeyboardState());
  }

  GameState setPlayer(Player newPlayer) {
    return new GameState(newPlayer, bullets, keyboard);
  }

  GameState setBullets(ImmutableSet<Bullet> newBullets) {
    return new GameState(player, newBullets, keyboard);
  }

  GameState setKeyboard(KeyboardState newKeyboard) {
    return new GameState(player, bullets, newKeyboard);
  }

  // Update the game state (repeatedly called for each game tick).
  GameState update() {
    GameState current = this;
    current = current.player.update(current);
    for (Bullet b : current.bullets)
      current = b.update(current);
    return current;
  }

  // Update the game state in response to a key press.
  GameState keyPressed(int key) {
    GameState current = this;
    current = keyboard.keyPressed(current, key);
    current = player.keyPressed(current, key);
    return current;
  }

  // Update the game state in response to a key release.
  GameState keyReleased(int key) {
    GameState current = this;
    current = keyboard.keyReleased(current, key);
    return current;
  }

  ImmutableImage render() {
    ImmutableImage img = new ImmutableImage(SpaceInvaders.W, SpaceInvaders.H);
    img = img.clear(Color.BLUE);
    img = player.render(img);
    for (Bullet b : bullets)
      img = b.render(img);
    return img;
  }
}

public class SpaceInvaders {
  static final int W = 640, H = 480;

  static GameState currentState = new GameState();

  public static void main(String[] _) {
    JFrame frame = new JFrame() {{
      setSize(W, H);
      setTitle("Space Invaders");
      setContentPane(new JPanel() {
        @Override public void paintComponent(Graphics g) {
          BufferedImage img = SpaceInvaders.currentState.render().backingImage;
          ((Graphics2D) g).drawRenderedImage(img, new AffineTransform());
        }
      });
      addKeyListener(new KeyAdapter() {
        @Override public void keyPressed(KeyEvent e) {
          currentState = currentState.keyPressed(e.getKeyCode());
        }
        @Override public void keyReleased(KeyEvent e) {
          currentState = currentState.keyReleased(e.getKeyCode());
        }
      });
      setLocationByPlatform(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);
    }};

    for (;;) {
      currentState = currentState.update();
      frame.repaint();
      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {}
    }
  }
}

2
मैंने कुछ जावा कोड जोड़े - क्या यह मदद करता है? यदि कोड अजीब लगता है, तो मैं अपरिवर्तनीय, कॉपी-ऑन-राइट कक्षाओं के कुछ छोटे उदाहरणों को देखूंगा। यह एक सभ्य व्याख्या की तरह लग रहा है।
डैनियल लुबरोव

2
@ chaotic3quilibrium यह एक सामान्य पहचानकर्ता है। argsयदि कोड तर्क को नजरअंदाज करता है तो मैं कभी-कभी इसका उपयोग करता हूं । अनावश्यक भ्रम के लिए क्षमा करें।
डैनियल लुबरोव

2
कोई चिंता नहीं। मैंने बस मान लिया और आगे बढ़ गया। मैंने कल के लिए आपके उदाहरण कोड के साथ खेला था। मुझे लगता है कि मेरे पास विचार का लटका हुआ है। अब, अगर मुझे कुछ और याद आ रहा है, तो मुझे आश्चर्य होगा। अस्थायी वस्तुओं की संख्या नम्र है। हर टिक एक फ्रेम उत्पन्न करता है जो एक गेमस्टेट प्रदर्शित करता है। और पिछले टिक के GameState से उस GameState को प्राप्त करने के लिए GameState के बीच में कई हस्तक्षेप करने वाले गेम उत्पन्न होते हैं, प्रत्येक में पिछले GameState से एक छोटा समायोजन होता है।
chaotic3quilibrium

3
हाँ, यह बहुत बेकार है। मुझे नहीं लगता है कि GameStateकॉपियाँ इतनी महंगी होंगी, भले ही प्रत्येक को प्रत्येक टिक किया जाए, क्योंकि वे प्रत्येक ~ 32 बाइट्स हैं। लेकिन एस की नकल करना ImmutableSetमहंगा हो सकता है यदि एक ही समय में कई गोलियां जीवित हों। हम समस्या को कम करने के लिए ImmutableSetएक पेड़ की संरचना के साथ बदल सकते हैं scala.collection.immutable.TreeSet
डैनियल लुबरोव

2
और ImmutableImageभी बदतर है, क्योंकि यह संशोधित होने पर एक बड़े रेखापुंज को कॉपी करता है। कुछ चीजें हैं जो हम उस समस्या को कम करने के लिए भी कर सकते हैं, लेकिन मुझे लगता है कि यह सिर्फ अनिवार्य शैली में प्रतिपादन कोड लिखने के लिए सबसे अधिक व्यावहारिक होगा (यहां तक ​​कि हास्केल प्रोग्रामर सामान्य रूप से ऐसा करते हैं)।
डैनियल लुबरोव

4

ठीक है, आप LWJGL का उपयोग करके अपने प्रयासों में बाधा डाल रहे हैं - इसके खिलाफ कुछ भी नहीं है, लेकिन यह गैर-कार्यात्मक मुहावरों को लागू करेगा।

आपका शोध मेरे सुझाव के अनुरूप है, हालाँकि। "इवेंट्स" कार्यात्मक प्रोग्रामिंग में कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग या डेटाफ्लो प्रोग्रामिंग जैसी अवधारणाओं के माध्यम से अच्छी तरह से समर्थित हैं। आप प्रतिक्रियाशील , स्कैला के लिए एक FRP लाइब्रेरी की कोशिश कर सकते हैं, यह देखने के लिए कि क्या इसमें आपके दुष्प्रभाव हो सकते हैं।

इसके अलावा, हास्केल से एक पृष्ठ लें: साइड इफेक्ट्स को अलग / अलग करने के लिए मोनड्स का उपयोग करें। राज्य और IO सनक देखें।


आपके उत्तर के लिए Tyvm मुझे यकीन नहीं है कि कीबोर्ड / माउस इनपुट और रिएक्टिव से ग्राफिक्स / ध्वनि आउटपुट कैसे प्राप्त करें। क्या यह वहाँ है और मैं इसे याद कर रहा हूँ? एक सनक का उपयोग करने के लिए आपके संदर्भ के अनुसार - मैं अभी उनके बारे में सीख रहा हूं और अभी भी पूरी तरह से समझ नहीं पाया कि एक सनक क्या है।
२०:२il बजे chaotic3quilibrium

3

गैर-निर्धारक भाग (मेरे लिए) उपयोगकर्ता इनपुट की धारा को संभाल रहे हैं ... आउटपुट (ग्राफिक्स और ध्वनि दोनों) को संभाल रहे हैं।

हां, आईओ गैर-नियतात्मक और "सभी के बारे में" साइड-इफेक्ट्स हैं। यह एक गैर-शुद्ध कार्यात्मक भाषा में एक समस्या नहीं है जैसे कि स्काला।

विदेशी बुलेट फायरिंग का निर्धारण करने के लिए एक यादृच्छिक मूल्य प्राप्त करना

आप एक छद्म आयामी संख्या जनरेटर के उत्पादन को एक अनंत अनुक्रम ( Seqस्काला में) के रूप में मान सकते हैं।

...

जहां, विशेष रूप से, क्या आप परिवर्तनशीलता की आवश्यकता देखते हैं? अगर मैं अनुमान लगा सकता हूं, तो आप अपने स्प्राइट्स को अंतरिक्ष में एक स्थिति के रूप में सोच सकते हैं जो समय के साथ बदलता रहता है। आपको इस तरह के संदर्भ में "ज़िपर्स" के बारे में सोचना उपयोगी हो सकता है: http://scienceblogs.com/goodmath/2010/01/zippers_making_functional_upda.php


मुझे यह भी पता नहीं है कि प्रारंभिक कोड को कैसे तैयार किया जाए ताकि यह मुहावरेदार कार्यात्मक प्रोग्रामिंग हो। उसके बाद, मैं "अशुद्ध" कोड में जोड़ने के लिए सही (या पसंदीदा) तकनीक को नहीं समझ रहा हूं। मुझे पता है कि मैं स्काला का उपयोग "अर्धविराम के बिना जावा" के रूप में कर सकता हूं। मैं ऐसा नहीं करना चाहता। मैं सीखना चाहता हूं कि कैसे एफपी समय या मूल्य उत्परिवर्तन लीक पर भरोसा किए बिना एक बहुत ही सरल गतिशील वातावरण को संबोधित करता है। क्या यह समझ में आता है?
२०:३il बजे chaotic3quilibrium
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.