2012-02-01 31 views
0

我正在研究這個程序,以更好地理解haskell和state monad。我做了一個模塊Rectangle,它具有數據類型Rectangle和一個函數來增加矩形的長度。爲了增加長度,我做了一個函數加。 難道還有比這個加功能更好的方法嗎?同時增加我正在添加一個新的矩形,這是邏輯上不正確的。 如何以正確的方式執行增量?有沒有什麼辦法,而不是給予默認寬度編譯器提示用戶的寬度? 如何在進行有狀態計算時提取一個或多個矩形或任何屬性(長度或寬度)?實現遞增函數

{-# LANGUAGE TemplateHaskell, TypeOperators #-} 
module Rectangle(Rectangle(Rectangle),GlobState(GlobState),plus,newGlobState,r1,r2,r3,incr) where 

import Control.Monad.State hiding (modify) 
import Data.Label (mkLabels) 
import Data.Label.Pure ((:->)) 
import Data.Label.PureM 

type Length = Int 
type Width = Int 

data Rectangle = Rectangle Length Width deriving (Eq,Read,Show) 

data GlobState = GlobState { _r1 :: Rectangle , _r2 :: Rectangle , _r3 :: Rectangle } deriving Show 
$(mkLabels [''GlobState]) 

plus :: Rectangle -> Rectangle -> Rectangle 
plus (Rectangle x z) (Rectangle y w) = Rectangle (x+y) z 

newGlobState:: GlobState 
newGlobState = GlobState { _r1 = Rectangle 0 10, _r2 = Rectangle 0 10, _r3 = Rectangle 0 10} 

incr :: (GlobState :-> Rectangle) -> State GlobState() 
incr x = modify x (plus (Rectangle 1 10)) 

我做了一個新的模塊選擇矩形的一個:

{-# LANGUAGE TemplateHaskell, TypeOperators #-} 
module ChooseRect(ChooseRect(ChooseRect),makeChoice,select) where 

import Rectangle 
import Control.Monad.State hiding (modify) 
import Data.Label (mkLabels) 
import Data.Label.Pure ((:->)) 
import Data.Label.PureM 

type Choice = Int 

data ChooseRect = ChooseRect Rectangle Rectangle deriving Show 

makeChoice:: Rectangle-> Rectangle->ChooseRect 
makeChoice p1 p2 = ChooseRect p1 p2 

select:: ChooseRect -> Choice -> Rectangle 
select (ChooseRect (Rectangle x z) (Rectangle y w)) choice = if (choice==1) 
       then let selectedRectangle = Rectangle x z 
       in selectedRectangle 
       else let selectedRectangle = Rectangle y w 
       in selectedRectangle 

但是,當我更改了主模塊I M得到錯誤。

module Main where 

import Rectangle 
import ChooseRect 
import Control.Monad.State hiding (modify) 
import Data.Label (mkLabels) 
import Data.Label.Pure ((:->)) 
import Data.Label.PureM 

main :: IO() 
main = do 
    let x = flip execState newGlobState $ do 
     incr r1 
     incr r2 
     incr r1 
     incr r3 
     incr r3 
    let y=makeChoice r1 r2 
    print y 
    print x 

的錯誤消息是

Couldn't match expected type `Rectangle' 
      with actual type `Data.Label.Abstract.Lens 
           (~>0) GlobState Rectangle' 
In the first argument of `makeChoice', namely `r1' 
In the expression: makeChoice r1 r2 
In an equation for `y': y = makeChoice r1 r2 

請解釋錯誤,以及如何將其刪除

+0

是否有意讓您的'incr'強制矩形的寬度爲10? (現在所有的矩形都有10的寬度,但是如果例如'r3'開始爲'Rectangle 0 5',你真的需要'incr'來使它成爲'Rectangle 1 10'嗎?) – dave4420 2012-02-01 10:14:52

+0

沒有..我想它是矩形1 5.這就是爲什麼我問我如何讓用戶輸入寬度 – 2012-02-01 10:17:51

+0

因此,不僅是'加號'邏輯不正確的類型,它也隱藏了一個錯誤。 – dave4420 2012-02-01 10:32:47

回答

3
  1. 優於你的plus將是一個lengthenBy :: Length -> Rectangle -> Rectangle

    哦,你使用modify錯......你需要使用從Control.Monad.State modifymodify從Data.Label.Pure。

    incr x = Control.Monad.State.modify $ Data.Label.Pure.modify x (lengthenBy 1) 
    
  2. 參見功能getLine :: IO String(用於獲取輸入的線)和read :: String -> Intreads :: String -> [(Int, String)](用於接通它從一個StringInt;前者是更簡單的使用,但崩潰,如果它不能解析輸入)(並且putStr :: String -> IO()putStrLn :: String -> IO()用於顯示提示)。

    n.b.在main的最外面的do-block中執行你的I/O,並把結果作爲額外的參數傳遞給你的 有狀態計算。

  3. 在類型替換

    makeChoice r1 r2 
    

    makeChoice (get r1 x) (get r2 x) 
    

    看:

    r1, r2 :: GlobState :-> Rectangle 
    makeChoice :: Rectangle -> Rectangle -> ChooseRect 
    

    所以r1r2是正確類型的未傳遞到makeChoice

+1

但是,如果我實現了像這樣的加號,它將與增量的定義衝突,其中加號被使用 – 2012-02-01 10:08:43

+1

這個想法是,你把'lengthenBy 1'而不是'plus(矩形1 10)'。 – dave4420 2012-02-01 10:12:11

+0

Bur代碼給出了進一步的錯誤是我這樣做... – 2012-02-01 11:33:34