2012-02-29 9 views
7

मैं एक साधारण हास्केल डेटाटाइप और एक समारोह को ओओ में बदलने की कोशिश कर रहा हूं। लेकिन मैं उलझन में हूँ ..हास्केल डेटाटाइप जावा (ओओ)

अंकगणितीय गणना के लिए निम्नलिखित हास्केल प्रकार है:

data Expr = Lit Int | 
     Add Expr Expr | 
    deriving Show 

--Turn the expr to a nice string 
showExpr :: Expr -> String 
showExpr (Lit n) = show n 
showExpr (Add e1 e2) = "(" ++ showExpr e1 ++ "+" ++ showExpr e2 ++ ")" 

अब मैं कन्वर्ट करने के लिए कोशिश कर रहा हूँ ..

public interface Expr { 
    String showExpr(String n); 
} 

// Base case 
public class Lit implements Expr { 
    String n; 

    public Lit(String n) { 
    this.n = n; 
    } 

    @Override 
    public String ShowExpr() { 
    return n; 
    } 
} 

public class Add implements Expr { 
    Expr a; 
    Expr b; 

    public Add(Expr aExpr, Expr bExpr) { 
    this.a = aExpr; 
    this.b = bExpr; 
    } 

    public String ShowExpr() { 
    return "(" + a.ShowExpr() + "+" + b.ShowExpr() + ")"; 
    } 

    public static void main(String[] args) { 
    Lit firstLit = new Lit("2"); 
    Lit secLit = new Lit("3"); 
    Add add = new Add(firstLit,secLit); 
    System.out.println(add.ShowExpr()); 
    } 
} 

इस का परिणाम देगा "(2 + 3) ", यह सही जवाब है।

लेकिन .. मुझे यकीन नहीं है .. क्या यह इसके बारे में सोचने और ओओ में मॉडल करने का सही तरीका है?

हास्केल डेटाटाइप का अच्छा प्रतिनिधित्व नहीं है?

+3

मुझे लगता है कि आपका रूपांतरण वास्तविक अच्छा है। एकमात्र चीज जिसे मैं टिप्पणी कर सकता हूं कि एक्सप्रेशंस को इंटरफेस के बजाय एक अमूर्त कक्षा होना चाहिए। और इस तरह की समस्याओं के लिए जावा का उपयोग न करें क्योंकि इस पर हैकेल बहुत बेहतर है। – nist

उत्तर

5

चलो कोड को जितनी जल्दी हो सके कॉपी करें।

यहाँ कुछ गुण है कि हास्केल डेटा संरचना है कर रहे हैं:

  1. यह प्रकार Expr और दो कंस्ट्रक्टर्स है Lit और Add
  2. आप जोड़ सकते हैं या "बाहर" से कंस्ट्रक्टर्स नहीं निकाल सकते

तो, यदि हम चाहते हैं कि ये गुण जावा संस्करण में सत्य रहें, तो आपको इसे ऐसा करना चाहिए:

public abstract class Expr { 
    // So that you can't add more subclasses outside this block 
    private Expr() {} 

    // Simulate pattern matching: 
    // (This CAN be done with instanceof, but that's ugly and not OO) 
    public boolean isLit() { 
     return false; 
    } 
    public boolean isAdd() { 
     return false; 
    } 
    public Lit asLit() { 
     throw new UnsupportedOperationException("This is not a Lit"); 
    } 
    public Add asAdd() { 
     throw new UnsupportedOperationException("This is not an Add"); 
    } 

    public static class Lit extends Expr { 
     public final int n; 
     public Lit(int n) { 
      this.n = n; 
     } 
     @Override 
     public boolean isLit() { 
      return true; 
     } 
     @Override 
     public Lit asLit() { 
      return this; 
     } 
    } 

    public static class Add extends Expr { 
     public final Expr a, b; 
     public Lit(Expr a, Expr b) { 
      this.a = a; 
      this.b = b; 
     } 
     @Override 
     public boolean isAdd() { 
      return true; 
     } 
     @Override 
     public Add asAdd() { 
      return this; 
     } 
    } 
} 

अब, showExpr कन्वर्ट करने के लिए:

public static String showExpr(final Expr expr) { 
    if(expr.isLit()) { 
     return Integer.toString(expr.asLit().n); 
    } else if(expr.isAdd()) { 
     return "(" + expr.asAdd().a + "+" + expr.asAdd().b + ")"; 
    } 
} 

आप Expr कक्षा में एक स्थिर पद्धति के रूप में showExpr डाल सकते हैं। मैं इसे एक उदाहरण विधि बनाउंगा, क्योंकि यह हास्केल संस्करण से आगे निकलता है।

+5

मुझे 'if (e.isLit()) {Lit l = e.asLit() के बीच कोई वास्तविक अंतर नहीं दिखता है; } 'और' अगर (ई उदाहरण के लिट) {लिट एल = (लिट) ई; } '। हास्केल-स्टाइल पैटर्न मिलान स्वाभाविक रूप से ओओ नहीं है, इसलिए उस तथ्य को छिपाने की कोशिश कर रहे हैं जो 'exampleof' और casts को अनुकरण करते हैं, कोड को कुछ भी नहीं लाता है। – yshavit

+0

@ यशवत, आप निश्चित रूप से सही हैं, लेकिन मुझे लगता है कि जो शैली मैं प्रस्तुत करता हूं वह आसानी से पढ़ने के लिए कोड की ओर जाता है, और कम अगर जैसे 'अगर (foo exampleof foo) {((bar) foo) .bla() ; } 'रिफैक्टरिंग के कारण (' फू! = बार')। उदाहरण के लिए मैं निजी कक्षाओं में 'एड' और 'लिट' बनाना चाहता हूं और उनके लिए कारखाने के तरीकों का उपयोग करना चाहता हूं, और उस स्थिति में, 'exampleof' काम नहीं करेगा। – dflemstr

+0

'e exampleof lit'' e.isLit() 'से अधिक या कम पठनीय है, मैं राय के मामले के रूप में छोड़ दूंगा। :) लेकिन ध्यान दें कि यदि वे निजी कक्षाएं हैं, तो 'e.asLit()। N' काम नहीं करेगा, या तो। – yshavit

2

मैं थोड़ा अपने सिर पर इस बारी जाएगा: प्रत्येक हास्केल वर्ग एक जावा इंटरफ़ेस हो जाता है, और instance ...where (या derives) implements हो जाता है।

तो, class Show a तो अब

interface Showable { 
    String show(); 
} 

हो जाता है, Expr डेटा प्रकार क्या क्या करता है? यह विभिन्न हास्केल रचनाकारों - उर्फ ​​जावा कक्षाओं को एक ही प्रकार में जोड़ता है, और यह भी कहता है कि वे सभी हास्केल कक्षाओं (यानी जावा इंटरफेस को लागू करते हैं) द्वारा कवर किए जाते हैं। तो, मैं तो कहूँगा कि डेटा प्रकार Expr

interface Expr extends Showable {} 

और Lit निर्माता बन जाता है, उदाहरण के लिए, हो जाता है:

class Lit implements Expr { 
    @Override 
    String show() { 
     ... 
    } 
} 

अब आप जावा संग्रह है कि दोनों Lit और Add उदाहरणों में शामिल हो सकता है (उदाहरण के लिए List<Expr>), और किसी भी Expr के लिए, आप इसे implements Showable जानते हैं।

ध्यान दें कि Showable को अपने स्वयं के इंटरफ़ेस के रूप में खींचकर (अपनी विधि को सीधे Expr पर डालने के बजाय), मैं अन्य, पूरी तरह से असंबंधित जावा कक्षाओं को इसे लागू करने की अनुमति देता हूं। यह आपके द्वारा परिभाषित किसी भी हास्केल क्लास के instance ... where को परिभाषित करने के समान है।

अंत में, यहां खुले दुनिया और बंद-दुनिया नीतियों के बीच कुछ विसंगतियां हैं। हास्केल का instance ... where खुला दुनिया है, जबकि जावा का implements बंद है। लेकिन हास्केल के रचनाकार-प्रति-प्रकार बंद हैं, जबकि जावा का extendsअधिकतर खुला है।

implements बंद होने के बारे में आप इतना कुछ नहीं कर सकते हैं, लेकिन आप extends को एक अमूर्त वर्ग और एक निजी निर्माता के साथ बंद कर सकते हैं, इसलिए मैं यही करूँगा (यदि आप उस व्यवहार को चाहते हैं)। उपरोक्त tweaking, हम पाते हैं:

public abstract class Expr implements Showable { 
    private Expr() { 
     // hide the ctor from the outside world, so nobody else 
     // can extend this class 
    } 

    public static class Lit extends Expr { 
     ... 
    } 

    public static class Add extends Expr { 
     ... 
    } 
} 
+0

यह ठीक होगा अगर मूल कोड एक प्रकार की कक्षा का उपयोग करेगा, लेकिन मुझे लगता है कि यह एक साधारण एडीटी मॉडलिंग के लिए अधिक है। – Landei

0

आपका कोड ठीक दिखता है, लेकिन थोड़ा और मूर्खतापूर्ण हो सकता है। खेतों को अपरिवर्तनीय बनाने के लिए आप final का उपयोग कर सकते हैं, उदाहरण के लिए। आप को toString (जिसे Object में घोषित किया गया है) के साथ प्रतिस्थापित कर सकते हैं, जब तक कि आप toString कुछ अलग करने के लिए नहीं चाहते हैं। String.format का उपयोग करके मेरी राय में कई तारों को संयोजित करने से थोड़ा क्लीनर है। अंत में, मेरे पास Litint स्टोर करेगा, क्योंकि यह अधिक कॉम्पैक्ट और सुरक्षित है।

यहां बताया गया है कि मैं यह अनुवाद होगा:

abstract class Exp { 
    // Force subclasses to override Object.toString. 
    public abstract String toString(); 
} 

class Lit extends Exp { 
    final int value; 

    Lit(int value) { 
    this.value = value; 
    } 

    public String toString() { 
    return Integer.toString(value); 
    } 
} 

class Add extends Exp { 
    final Exp a, b; 

    Add(Exp a, Exp b) { 
    this.a = a; 
    this.b = b; 
    } 

    public String toString() { 
    return String.format("(%s + %s)", a, b); 
    } 
} 

class Main { 
    public static void main(String[] args) { 
    Lit firstLit = new Lit(2); 
    Lit secLit = new Lit(3); 
    Add add = new Add(firstLit, secLit); 
    System.out.println(add); 
    } 
} 
1

मैं इसे इस तरह से अनुवाद होगा:

public abstract class Expr { 

    public static Expr Lit(final int n) { 
     return new Expr() { 
      public String showExpr() { 
       return "" + n; 
      } 
     }; 
    } 

    public static Expr Add(final Expr e1, final Expr e2) { 
     return new Expr() { 
      public String showExpr() { 
       return String.format("(%s+%s)", e1.showExpr(), e2.showExpr()); 
      } 
     }; 
    } 

    public abstract String showExpr(); 

    public static void main(String[] args) { 
     Expr firstLit = Lit(2); 
     Expr secLit = Lit(3); 
     Expr add = Add(firstLit, secLit); 
     System.out.println(add.showExpr()); 
    } 
} 

हास्केल Lit में और Add कोई उपप्रकार हैं (वहाँ हास्केल में ऐसी कोई बात नहीं है), लेकिन बस Expr संस्करण। जावा में उप-वर्गों का पर्दाफाश करने की कोई आवश्यकता नहीं है, इसलिए मैं कुछ तरीकों से छिपी अज्ञात कक्षाओं का उपयोग क्यों कर सकता हूं। यह सही काम करता है, जब तक आपको पैटर्न मिलान की आवश्यकता नहीं होती है (जिसे जावा में मॉडल करना मुश्किल है, क्योंकि सरल instanceof परीक्षण अधिक जटिल उदाहरणों के साथ जल्द ही गन्दा हो जाता है)।

संबंधित मुद्दे