2014-07-23 24 views
1

我有幾個問題哈斯克爾寫構造函數做他們的工作

我寫這個構造被稱爲繩,我有這樣的

data Rope = TextRope{ropeText :: String} 
      | ConcatRope{rope1 :: Rope, rope2 :: Rope} 
      | SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer} 
      deriving Show 

首先,當我作出這樣

一個TextRope
*Main> let s =TextRope "why" 
*Main> s 
TextRope {ropeText = "why"} 
*Main> 

當我做矽只想得到構造函數的字符串,這是爲什麼,我不知道這一點。

也對concat和子構造函數感到好奇。具體來說,在我看來,你調用這兩個構造函數的時候發生了一些事情,你將返回連接繩索1和繩索2的結果,我不知道如何用這種語言描述,你正在定義數據結構,但不知何故的的回報是,必須通過結構

這裏來計算是一些例子的結果是什麼,這些功能是如何工作的

> let tr = TextRope "Hello," 
> let sr = TextRope " world!" 
> let hw = ConcatRope tr sr 
> let ow = SubRope hw 4 4 
> tr 
Hello, 
> sr 
world! 
> hw 
Hello, world! 

排序的困惑總體而言,新的哈斯克爾構造函數和數據類型,所以一些指針會有所幫助(不是c指針雖然!)

+2

Haskell構造函數不像Java或C++構造函數。相反,它們更像是一個標記聯盟中的「標籤」。他們不是「做事」,而是「聲明形狀」。 –

回答

5

數據構造永遠不會做的工作。他們只保存你傳遞給他們的數據。如果你想完成工作,你應該定義所謂的智能構造函數,它們只是在將函數傳遞給實際構造函數之前執行某些操作的函數。一個例子可能是

data Fraction = Fraction 
    { numerator :: Int 
    , denominator :: Int 
    } deriving (Eq) 

(%) :: Int -> Int -> Fraction 
x % y = 
    let (a, b) = reduce x y 
    in Fraction a b 

-- Reduces a fraction to it's simplest terms 
reduce :: Int -> Int -> (Int, Int) 
reduce num den = undefined 

在這裏,你不會從你的模塊,只需將%功能構建一個最簡化形式導出Fraction構造。

您遇到的另一個問題是您希望構造函數以不同的方式打印出來。您可以通過不派生Show來實現此目的。不過,我會警告說,Haskell約定是show . read = read . show = id,它不適合你想要做的事情。這不是一個嚴格的約定,不過,並沒有什麼東西做這樣的事情阻止你:

data Rope = <your implementation minus the deriving Show bit> 

instance Show Rope where 
    show (TextRope t) = t 
    show (ConcatRope r1 r2) = show r1 ++ show r2 
    show (SubRope r starting ending) = <exercise left to reader> 

順便說一句,我會建議對具有記錄不同的字段名稱和類型,這可能會導致程序類型檢查時出現問題,但是如果寫入方式不同,則可能會在編譯時捕獲錯誤。例如,如果您有代碼,將會發生什麼情況

> ropeText (ConcatRope (TextRope "Hello, ") (TextRope "world!")) 

這會導致錯誤並導致程序崩潰!取而代之的是,它看起來像你只想要一個Rope型與concatsubRope功能,讓你可以實現很簡單地作爲

data Rope = Rope String deriving (Eq) 

concatRope :: Rope -> Rope -> Rope 
concatRope (Rope r1) (Rope r2) = Rope (r1 ++ r2) 

-- Why use Integer instead of Int? You might find it's easier to implement this function 
subRope :: Rope -> Integer -> Integer -> Rope 
subRope (Rope r) start end = Rope $ substr start end r 
    where substr s e text = <exercise left to reader> 

現在絕對沒有辦法有一個非法的繩索操作,唯一的區別是現在你必須使用concatRope代替ConcatRopesubRope代替SubRope。你可以保證這些函數能夠完成你想要的功能,但是你沒有一些複雜的類型無法幫助你。

+0

非常感謝你的洞察力,這非常有幫助。 – Eigenvalue

+1

@Eigenvalue我會補充一點,記住在Haskell中,數據類型只是一個用於保存值的結構,而不是更多。在Haskell中,我們盡最大努力將數據的定義與我們想要對其執行的操作分開。在大多數OOP語言中,結構和操作緊密結合在同一個定義中。雖然兩者都有優勢,但是當您可以用數學方法證明構造類型值的任何函數生成有效結構時,可以更輕鬆地推理代碼,從而讓您更容易地跟蹤錯誤。 – bheklilr

2

如果你不imp借你自己的節目(而不是自動派生),你將很難得到你想要的東西。

但是,如果你很容易kindof:

data Rope = TextRope{ropeText :: String} 
      | ConcatRope{rope1 :: Rope, rope2 :: Rope} 
      | SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer} 

instance Show Rope where 
    show (TextRope s) = s 
    show (ConcatRope a b) = show a ++ show b 

我敢肯定,你會發現在SubRope情況youself實施;)

0

您的示例代碼和示例交互式結果不匹配。這是你如何定義Rope

data Rope = TextRope{ropeText :: String} 
      | ConcatRope{rope1 :: Rope, rope2 :: Rope} 
      | SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer} 
      deriving Show 

deriving Show部分是關鍵那裏。我們會看到如何。

後來你看這個例子輸出:

> let tr = TextRope "Hello," 
> let sr = TextRope " world!" 
> let hw = ConcatRope tr sr 

> hw 
Hello, world! 

有了,我只是顯示的代碼,實際上,你會看到如下:

> hw 
ConcatRope { rope1 = TextRope "Hello,", rope2 = TextRope " world!" } 

的唯一途徑,我們可以得到你描述的輸出是如果我們擺脫了Rope的定義中的deriving Show子句,並且寫道:

instance Show Rope where 
    show (TextRope text) = text 
    show (ConcatRope r1 r2) = show r1 ++ show r2 
    show (SubRope rope start end) = ...