Monade (Informatik)

In der funktionalen Programmierung sind Monaden ein abstrakter Datentyp. Historisch wurde der Begriff Monad auch als Name für X in einer mathematischen Gleichung verwendet. Wesentliche Eigenschaft von Monaden ist die Fähigkeit der Übertragung von Werten und Berechnungen eines „einfacheren“ Typs zu Berechnungen eines „höheren“ Typs, der mittels eines Typkonstruktors aus dem einfacheren Typ hervorgeht, sowie die Verknüpfung mehrerer solcher Übertragungen zu einer einzigen.

Hintergrund

Der Hauptnutzen von Monaden ist es, Ein- und Ausgabeoperationen, zustandsbehaftete Berechnungen, Nichtdeterminismus (auch als Iteration über Kollektionen und ihren Kombinationen interpretierbar) und Anderes auszudrücken. Dabei soll die Sprache keine Nebeneffekte einführen.[1]

Das Konzept der Monade stammt aus der Kategorientheorie, einem Zweig der Mathematik, welcher mathematische Objekte mittels Morphismen oder Funktoren vergleicht. Die Wörter Monade oder aber auch Funktor sind wiederum von Konzepten in der Philosophie abgeleitet.

Die Programmiersprache Haskell ist eine funktionale Sprache, die Monaden stark einsetzt und versucht, monadische Kompositionen zu vereinfachen, beispielsweise durch syntaktischen Zucker (u. a. die sogenannte do-Notation).

Definitionen

Die übliche Formulierung einer Monade in der Programmierung hat folgende Komponenten:

  1. Ein Typkonstruktor, der für jeden zugrunde liegenden Typ definiert, wie der korrespondierende Monadentyp zu erhalten ist. Der Name dieses Typkonstruktors wird dabei oft synonym mit der ganzen Monade verwendet. Wenn M der Name der Monade und t der Datentyp ist, so ist M t der korrespondierende monadische Typ.
  2. Eine Einheitsfunktion, die einen Wert des zugrunde liegenden Typs auf den Wert des korrespondierenden Monadentyps abbildet. Das Ergebnis ist der "einfachste" Wert im korrespondierenden Typ, der sich aus dem Originalwert gewinnen lässt. In Haskell wird diese Funktion return genannt. Die Einheitsfunktion hat den polymorphen Typ t→M t.
  3. Mindestens eine weitere Operation (siehe dazu die folgenden Abschnitte), welche die Verknüpfung monadischer Operationen beschreibt.

Die folgenden Operationen sind typisch für Monaden und können für deren Definition Verwendung finden:

  1. Die Einheitsfunktion
    return :: a -> m a
    
  2. Der bind-Operator
    (>>=) :: m a -> (a -> m b) -> m b
    
    erlaubt, einen monadischen Typ an eine Funktion zu übergeben, die nur den zugrundeliegenden Typ verwendet. Sein erstes Argument ist ein Wert von monadischem Typ und sein zweiter ist eine Funktion, die vom zugrunde liegenden Typ des ersten Arguments auf einen anderen monadischen Typ abbildet. Der Rückgabewert ist vom anderen Monadentyp.
  3. Der Kleisli-Operator
    (>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)
    
    realisiert eine Komposition (Hintereinanderausführung) für Funktionen, die einen monadischen Typ zurückgeben, aber nur den jeweils zugrundeliegenden Typ verwenden.
  4. Der Funktor
    fmap :: (a -> b) -> m a -> m b
    
    erlaubt, einen monadischen Typ an eine Funktion zu übergeben, die nur den zugrundeliegenden Typ verwendet. Sein erstes Argument ist eine Funktion f, von einem beliebigen Typ a auf einen beliebigen Typ b abbildet. Sein zweites Argument ist ein Wert von einem monadischen Typ, dem der Typ a des Argumentes von f zugrunde liegt. Der Rückgabewert ist von einem monadischen Typ, dem der Typ b des Rückgabewertes von f zugrunde liegt.
  5. Eine natürliche Transformation
    join :: m (m a) -> m a
    
    , welche ein „Abflachen“ des monadischen Typs um eine Verschachtelungsebene erlaubt (dabei steht m für den Typkonstruktor).

Diese Operationen müssen folgenden Gesetzen gehorchen:

  1. "Assoziativität" von >>=
      (ma >>= f) >>= g == ma >>= ( \a -> ((f a) >>= g) )
    
  2. Assoziativität von >=>
      (f >=> g) >=> h  == f >=> (g >=> h)
    
  3. Kompatibilität von Verkettung und fmap
          fmap (f . g) == (fmap f) . (fmap g)
    
  4. join ist eine natürliche Transformation von fmap . fmap auf fmap
       (fmap f) . join == join . ((fmap . fmap) f)
    
  5. Kommutativität von fmap und join
          join . join  == join . (fmap join) -- das zweite join hat den typ m (m (m a)) -> m (m a)
    
  6. return ist eine natürliche Transformation von id auf fmap
     (fmap f) . return == return . f
    
  7. Neutralität von return unter >>=
          ma >>= return == ma
       (return a) >>= f == f a
    
  8. Neutralität von return unter >=>
          f >=> return == return >=> f == f
    
  9. Neutralität von return unter >=>, in fmap/join-Notation
         join . return == join . (fmap return) == id
    

In Anlehnung an Haskell

In Haskell wird eine Monade über die Operationen return und (>>=) definiert:

class Monad m where
  return ::   a -> m a
  (>>=)  :: m a -> (a -> m b) -> m b

Die anderen Operationen lassen sich dann über diese beiden definieren:

(f >=> g) a = f a >>= g
(fmap f) ma =  ma >>= (return . f)
   join mma = mma >>= id

Über den Kleisli-Operator

Eine Monade lässt sich auch über ihre Kleisli-Kategorie definieren:

class Monad m where
  return ::  a -> m a
  (>=>)  :: (a -> m b) -> (b -> m c) -> (a -> m c)

Die übrigen Operationen ergeben sich dann wie folgt:

   ma >>= f = (id >=>  f)  ma
     fmap f =  id >=> (return . f)
       join =  id >=> id

Analog zur Kategorientheorie

In der Kategorientheorie wird eine Monade üblicherweise über einen Funktor fmap sowie zwei natürliche Transformationen return und join definiert:

class Monad m where
  fmap   :: (a -> b) -> m a -> m b
  return ::       a  ->  m a
  join   ::  m (m a) ->  m a

Die übrigen Operationen lassen sich dann wie folgt realisieren:

   ma >>= f = (join . (fmap f)) ma
    f >=> g =  join . (fmap g) . f

Beziehungen zu anderen Typklassen

Jede Monade ist auch ein Applikativer Funktor und mithin auch ein Funktor. Umgekehrt gilt das nicht.

Diese Eigenschaft fand sich aus historischen Gründen nicht explizit in Haskells Standardbibliothek, der Glasgow Haskell Compiler hat dies jedoch mit Version 7.10 eingeführt.[2]

Besonders deutlich wird diese Beziehung auch, vergleicht man die kategorientheoretische Definition mit der Funktor-Klasse in Haskell:

class Functor f where
  fmap   :: (a -> b) -> f a -> f b

Dabei muss fmap ebenfalls die Kompatibilitätsbedingung mit der Komposition (.) erfüllen.

Beispiele

Behälter

Container wie Listen, Mengen, Multimengen stellen Monaden dar, deren Bindeoperation die übergebene Funktion auf alle Elemente anwendet und die dabei erhaltenen Ergebnisse vereinigt. Die Vereinigungsoperation ist dabei jeweils Listenverkettung, Vereinigungsmengenbildung bzw. Bildung der Multimengenvereinigung. Die Einheitsfunktion ergibt Einermengen und -listen.

Hier als Beispiel die Monade für verkettete Listen. Das Konzept der Instanz für Listen ist es, eine Liste einzulesen, dann jedes Element an die Funktion zu übergeben und die Ergebnisse zu verbinden. Hier eine Beispielimplementation in Haskell:

-- Hier nochmal zur Erinnerung, der Listentyp ist folgendermaßen definiert:
data [a] = [] | a:[a]
-- Als syntaktischer Zucker kann [a,b,c] für a:b:c:[] verwendet werden.

instance Monad [] where
--return :: a -> [a]
  return a = [a] -- Per Definition eine Liste mit einem Element zurückgeben
--(>>=) :: [a] -> (a -> [b]) -> [b]
  liste >>= f  = concat zwischenergebnis where -- Die einzelnen Teillisten zusammenfügen
    zwischenergebnis :: [[b]]
    zwischenergebnis = map f liste -- Die Funktion auf die Liste abbilden

Vektoren und lineare Abbildungen

Der Typkonstruktor bildet hier einen Typ auf einen Vektorraum ab, bei dem als (Namensgeber für eine) Basis dient, und dessen Elemente beispielsweise als Funktionen modelliert werden. Die Bindeoperation hat den Typ . Durch Vertauschen der Argumente erhält man den Typ , an dem man die Semantik erkennen kann: die gegebene Funktion, die auf den Basiselementen definiert ist, wird zu einer vollen linearen Abbildung erweitert. Die Einheitsfunktion bildet das Basiselement (welches in dieser Modellierung noch kein „richtiger“ Vektor ist) auf den entsprechenden Basisvektor ab.

State, I/O

Bei zustandsbehafteten Aktionen dient die Bindeoperation der Verwirklichung der Hintereinanderausführung. Die Einheitsfunktion erstellt eine Aktion, die nichts tut und ein festes Resultat zurückgibt.

Das Konzept ist dabei recht natürlich. Wenn man in einer rein funktionalen Programmiersprache einen veränderlichen Status übergeben will, dann macht man das in der Regel auf folgende Weise, hier am Beispiel einer Zählerfunktion:

-- Den Zähler hochzählen und den alten Zähler zurückgeben
hochzählen :: Int -> Int -> (Int,Int)
hochzählen schrittweite zählerstand = (zählerstand,neuerZählerstand) where ...

Das Grundprinzip ist, dass man als Parameter den alten Status anhängt und den neuen mit dem Rückgabewert zusammen zurückgibt. Um sich Arbeit zu ersparen, kann man dieses Muster einfach in einen neuen Typen verpacken, der Parameter s des Types ist der Typ des Status, a ist der Parameter des Rückgabewertes:

data Status s a = Status (s -> (a,s))

-- Beispiel:
hochzählen :: Int -> Status Int Int
hochzählen schrittweite = Status $ \zählerstand -> (zählerstand,zählerstand+schrittweite)

Was man jetzt noch braucht, sind ein paar Funktionen, die den Status manipulieren können. Hier zum Beispiel eine Funktion, die den Status auf einen neuen setzt, und eine, die ihn ausliest:

setStatus :: s -> Status s ()
setStatus s = Status $ \_ -> ((),s) -- Der alte Status wird ignoriert und durch den neuen ersetzt. Rückgabewert, da unnötig, ().

getStatus :: Status s s
getStatus = Status $ \s -> (s,s) -- Dupliziere den Status in den Rückgabewert.

Dies ist schon fast alles, was nötig ist. Das einzige, was noch fehlt, ist die Möglichkeit mehrere statusverändernde Aktionen zu kombinieren, hier sind Monaden das Werkzeug der Wahl:

instance Monad (Status s) where -- Die Typvariable  s ist irrelevant für die Definition
--return :: a -> Status s a
  return a = Status $ \s -> (a,s) -- Status bleibt unverändert
--(>>=)  :: Status s a -> (a -> Status s b) -> Status s b
  (Status aktion1) >>= f = Status $ \s -> aktion2 zwischenstatus where -- Status aus aktion1 in aktion2 einspeisen.
    (rückgabe1,zwischenstatus) = aktion1 s   -- aktion1 ausführen
    Status aktion2              = f rückgabe1 -- Rückgabewert aus aktion1 in f einspeisen

Mit diesen Funktionen und dem syntaktischen Zucker der do-Notation (der die monadischen Operationen vor uns versteckt) lässt sich das Beispiel dann folgendermaßen formulieren:

hochzählen :: Int -> Status (Int,Int)
hochzählen schrittweite = do zählerstand <- getStatus -- Zählerstand ermitteln
                             setStatus (zählerstand + schrittweite) -- Zähler setzen
                             return zählerstand -- alten Zählerstand zurückgeben

-- Hier entzuckert
hochzählen schrittweite = getStatus >>= \zählerstand ->
                          setStatus (zählerstand + schrittweite) >>= \_ ->
                          return zählerstand


Andere Sprachen

LINQ-Abfrageausdrücke in C# sind direkt inspiriert von Haskells do-Notation.[3] Ein Analogon zur Typklasse Monad ist in C# jedoch nicht ausdrückbar; der Compiler übersetzt LINQ-Abfrage-Ausdrücke blind in Aufrufe von Methoden mit festgelegten Namen. Diese sind Select und SelectMany. Auch benutzerdefinierte Klassen können also mittels LINQ-Abfrageausdrücken angesprochen werden, wenn diese Methoden mit entsprechenden Namen zur Verfügung stellen.

Dieselbe Strategie verfolgt Scala im Fall von for-Comprehensions.[4] Die Methoden heißen da map und flatMap.

In der Standardbibliothek von Java 8 sind mindestens zwei Monaden vorhanden, die derselben Namenskonvention gehorchen: die Schnittstellen Optional und Stream definieren Methoden namens map, flatMap und of.

Monaden in anderen Programmiersprachen

Groovy
  • Monads in Groovy[5]
Python
  • Monads in Python[6]
Scala
  • Monads in Scala[7]
Clojure
  • Monads in Clojure[8]
JavaScript
  • Monads in JavaScript[9]
C#

Einzelnachweise

  1. Simon L. Peyton Jones, Philip Wadler: Imperative Functional Programming. Conference record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Charleston SC 1993
  2. https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/release-7-10-1.html
  3. Erik Meijer: The World According to LINQ. (acm.org).
  4. http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html
  5. Monads in Groovy
  6. Monads in Python
  7. Monads in Scala (Memento des Originals vom 7. Juni 2011 im Internet Archive)  Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis.@1@2Vorlage:Webachiv/IABot/lamp.epfl.ch
  8. Monads in Clojure
  9. Monads in JavaScript (Memento vom 22. Dezember 2010 im Internet Archive)
  10. Wes Dyer: The Marvels of Monads. In: Yet Another Language Geek. MSDN Blogs, Microsoft, 10. Januar 2008, abgerufen am 21. März 2013.
  11. Mike Hadlow: Monads in C#. In: Code Rant. 9. Januar 2011, abgerufen am 21. März 2013.
  12. Muraad Nofal: Monads-CSharp. In: GitHub. 10. März 2014, abgerufen am 21. März 2013.

Read other articles:

For other uses, see Gigantic (disambiguation). 2008 American filmGiganticTheatrical release posterDirected byMatt AseltonWritten byMatt AseltonAdam NagataProduced byMindy GoldbergChristine VachonStarringPaul DanoZooey DeschanelEdward AsnerJane AlexanderJohn GoodmanCinematographyPeter DonahueEdited byBeatrice SisulMusic byRoddy BottumDistributed byFirst Independent PicturesRelease dates September 8, 2008 (2008-09-08) (TIFF) April 3, 2009 (2009-04-03) (Unit...

 

مسجد الدليجان (ديم خزام) معلومات عامة القرية أو المدينة البصرة/ الزبير الدولة العراق تاريخ بدء البناء 1311 هـ/1893م المواصفات المساحة 625م2 عدد المصلين 300 عدد المآذن 1 التفاصيل التقنية المواد المستخدمة الطابوق التصميم والإنشاء النمط المعماري إسلامية المقاول محمد بن فوزان الدليجا

 

Nature reserve in Italy Regional Natural Park of the Ligurian AlpsParco Naturale Regionale delle Alpi LiguriIUCN category V (protected landscape/seascape)The ridge from Cima Garlenda to Monte FrontèLocationImperia Province, ItalyNearest cityVentimiglia and SanremoCoordinates44°00′27.11″N 07°41′40.34″E / 44.0075306°N 7.6945389°E / 44.0075306; 7.6945389Area6,041 ha (14,930 acres)Established2007Governing bodyEnte Parco delle Alpi Liguri (Pigna)...

1954 film The Rainbow JacketOriginal UK quad format posterDirected byBasil DeardenWritten byT.E.B. ClarkeProduced byMichael Balcon Michael RelphStarringKay Walsh Bill Owen Edward UnderdownRobert Morley Honor BlackmanCinematographyOtto HellerEdited byJack HarrisMusic byWilliam AlwynProductioncompanyEaling StudiosDistributed byGeneral Film DistributorsRelease date 27 May 1954 (1954-05-27) ([1]) Running time99 minutesCountryUnited KingdomLanguageEnglish The Rainbow Jac...

 

110th Guards Rifle DivisionActive1943–1946Country Soviet UnionBranch Red Army (1943-46)TypeDivisionRoleInfantryEngagementsBattle of the DnieprKremenchug-Pyatikhatki OffensiveKirovograd offensiveUman–Botoșani offensiveFirst Jassy–Kishinev OffensiveSecond Jassy–Kishinev OffensiveBudapest OffensiveBattle of DebrecenSiege of BudapestBratislava–Brno offensivePrague OffensiveSoviet invasion of ManchuriaDecorations Order of the Red Banner Order of SuvorovBattle honours...

 

Alexander McQueen Información personalNombre de nacimiento Lee Alexander McQueen Nacimiento 17 de marzo de 1969 Lewisham (Reino Unido) Fallecimiento 11 de febrero de 2010 (40 años)Mayfair (Reino Unido) Causa de muerte Ahorcamiento Sepultura Kilmuir Nacionalidad BritánicaLengua materna Inglés FamiliaPadres Ronald McQueenJoyce McQueenCónyuge George Forsyth (2000-2001)EducaciónEducado en Central Saint MartinsRokeby School Información profesionalOcupación Diseñador, diseñador de moda y ...

Fuerzas Armadas de México Activa 1821País  MéxicoRama/s Ejército Mexicano Fuerza Aérea Mexicana Armada de MéxicoTipo Fuerzas armadasAlto mandoComandante supremo Andrés Manuel López ObradorSecretario de la Defensa Nacional Luis Cresencio SandovalSecretario de Marina José Rafael Ojeda DuránPersonalEdad 18 añosPersonal 354 180 (2023)[2]​[3]​Reserva 65 000 (2022)[1]​PresupuestoCantidad US$ 7 939 672 721 (2023)[4]​PIB 0.60 %...

 

Ini adalah daftar 151 komune di département Vaucluse, Prancis. (CAA) Komunitas aglomerasi Avignon Raya, dibentuk tahun 2001, juga sebagian di departemen Gard. (CAC) Komunitas aglomerasi Ventoux Comtat Venaissin, dibentuk tahun 2003. (CAP) Komunitas aglomerasi Pays d'Aix-en-Provence, dibentuk tahun 2001, kebanyakan di departemen Bouches-du-Rhone. Kode INSEE Kode pos Komune 84001 84210 Althen-des-Paluds 84002 84240 Ansouis 84003 84400 Apt 84004 84810 Aubignan (CAC) 84005 84390 Aurel 84006 8440...

 

Slovak football manager Karol Bučko Managerial careerYears Team1951–1952 Sokol NV Bratislava Slávia Bratislava TTS Trenčín1959–1963 FC Nitra Inter Bratislava VSS Košice1969–1972 SK Brann1972 Banik Ostrava Karol Bučko is a Slovak former football manager. He coached Sokol NV Bratislava, Slávia Bratislava, TTS Trenčín, FC Nitra,[1] Inter Bratislava, Banik Ostrava and VSS Košice.[2] References ^ FC Nitra : SPLASH. Fcnitra.sk. Archived from the original on 2013...

Season of television series Criminal Minds Season of television series Criminal Minds: EvolutionSeason 16Logo for the sixteenth seasonStarring Joe Mantegna A. J. Cook Kirsten Vangsness Aisha Tyler Adam Rodriguez Paget Brewster Country of originUnited StatesNo. of episodes10ReleaseOriginal network Paramount+ (U.S.) Disney+ (international) Original releaseNovember 24, 2022 (2022-11-24) –February 9, 2023 (2023-02-09)Season chronology← PreviousSeason 15List of episodes The...

 

This article relies largely or entirely on a single source. Relevant discussion may be found on the talk page. Please help improve this article by introducing citations to additional sources.Find sources: List of invitees for AMPAS Membership 2004 – news · newspapers · books · scholar · JSTOR (November 2019) The list of those invited to join the Academy of Motion Picture Arts and Sciences as members in 2004.[1] Actors Shohreh Aghdashloo Pa...

 

Ada Watney, c. 1900 Ada Annie Watney (née Nunn, later Weguelin) (1868-1938) was a founding member and committee member in the Ladies' Automobile Club (as Mrs Bernard Weguelin).[1][2] It was reported in 1904 that she had driven nearly 60,000 miles in six years. Early life Ada Nunn was born in 1868 to an English father and a Portuguese mother.[3] Marriages On 15 August 1889 at St Luke's Church, London, Ada Annie Nunn aged 21, reputed to be a former ballet-dancer had mar...

Artikel ini membutuhkan rujukan tambahan agar kualitasnya dapat dipastikan. Mohon bantu kami mengembangkan artikel ini dengan cara menambahkan rujukan ke sumber tepercaya. Pernyataan tak bersumber bisa saja dipertentangkan dan dihapus.Cari sumber: Episkopal – berita · surat kabar · buku · cendekiawan · JSTOR Halaman ini berisi artikel tentang bentuk tata kelola gereja. Untuk gereja-gereja yang dicirikan dengan bentuk ini dan menamakan diri Episkopalian...

 

This article contains content that is written like an advertisement. Please help improve it by removing promotional content and inappropriate external links, and by adding encyclopedic content written from a neutral point of view. (November 2018) (Learn how and when to remove this template message) Snakk Media LimitedTypePublicTraded asNZX: SNK(Suspended)[1]IndustryMobile advertisingFoundedNew Zealand (2010)HeadquartersAuckland, New ZealandArea servedAustralia, New Zealand, Southeast ...

 

Coordinator and communicator between organizations Naval liaison officers from Malaysia and Thailand coordinate efforts A liaison officer is a person who liaises between two or more organizations to communicate and coordinate their activities on a matter of mutual concern. Generally, liaison officers are used for achieving the best utilization of resources, or employment of services of one organization by another. Liaison officers often provide technical or subject matter expertise of their p...

Field Marshalจอมพล, จอมพลทหารบกRank flag of a Thai Field MarshalRank insignia of a Thai Field MarshalCountry ThailandService branch Royal Thai ArmyRank groupGeneral officerRankFive-star rankFormation1888Next higher rankHead of the Armed ForcesNext lower rankGeneralEquivalent ranksAdmiral of the Fleet (RTN)Marshal of the Air Force (RTAF) The Thai rank of Field Marshal (Thai: จอมพล, romanized: Chom Phon) is the most senior rank of the Roy...

 

1985 Indian filmPadikkadha PannaiyarPosterDirected byK. S. GopalakrishnanWritten byK. S. GopalakrishnanProduced byG. SulochanaStarringSivaji GanesanK. R. VijayaCinematographyDuttEdited byR. DevarajanMusic byIlaiyaraajaProductioncompanyKarpaga Lakshmi PicturesRelease date 23 March 1985 (1985-03-23) CountryIndiaLanguageTamil Padikkadha Pannaiyar (transl. Uneducated Landlord) is a 1985 Indian Tamil-language drama film, directed by K. S. Gopalakrishnan and produced by G. Sulo...

 

برج مراقبة مطار Bordeaux–Mérignac بفرنسا.   هذه المقالة عن برج مراقبة جويّة. لبرج الحصن أو برج دفاعي، طالع برج (توضيح).في الطيران، برج المراقبة هو برج تقع فيه وحدة مراقبة جوية وتعمل على السيطرة على حركة الطائرات داخل المطار وحوله.[1][2][3] انظر أيضاً طالعة موقف الط...

28978 إكسيون الاكتشاف المكتشف مسح بروجي عميق،  ومارك ويليام بوي  موقع الاكتشاف مرصد كرو تولولو تاريخ الاكتشاف 22 مايو 2001  الأسماء البديلة 2001 KX76  فئةالكوكب الصغير بلوتينو،  وجرم وراء نبتوني  الأوج 49.331 وحدة فلكية[1]،  و49.28588934870044 وحدة فلكية  الحضيض 30.0930600 و...

 

Pet supplies company headquartered in Montreal, Quebec, Canada This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages) This article contains content that is written like an advertisement. Please help improve it by removing promotional content and inappropriate external links, and by adding encyclopedic content written from a neutral point of view. (January 2016) (Learn how and when to remove this...

 

Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!