2017-05-27 56 views
1

我想在Haskell中編程成本函數,但似乎我高估了模式匹配的功能。這是我已經定義的代碼:編程成本函數的最佳方式(相關函數 - 值)

-- Directions for the movement 
data Direction = North | East | West | South deriving (Show, Eq) 

-- An `Action` gets a Coord and returns another Coord if possible 
type Action = Coord -> Maybe Coord 

-- Move function; `move North` is an Action 
move :: Direction -> Action 
move d (x, y) = ... 

我的主要問題是,現在我必須定義一個Cost功能使得:

type Cost = Coord -> Action -> Double 

在情況下,我想有一個簡單的成本函數只檢查方向返回一個成本,即來到了我的腦海裏第一個想法是利用模式匹配的,但這是無效的語法(和說實話,它似乎很公平):

mazeCost :: Cost 
mazeCost (x, y) (move East) = 3 
mazeCost (x, y) (move West) = 5 
-- ... And on and on 

我目前的解決方案涉及到計算目標狀態,並將其與每個操作的結果進行比較,以檢查這是否是作爲參數傳遞的函數,但這看起來很亂,並不是超級簡短的,我認爲也許有很多更好的方式來做到這一點在Haskell:

mazeCost :: Cost 
mazeCost coord action 
    | destination == east = 1 
    | destination == west = 2 
    | destination == north = 3 
    | destination == south = 0 
    where destination = action coord 
     east = move East coord 
     west = move West coord 
     south = move South coord 
     north = move North coord 

有沒有更好的方式與成本值(Double)的函數(Coord -> Direction -> Maybe Coord)相關聯?這是我試圖編寫的一個簡單示例,如果示例代碼中存在任何不一致或者不清楚,請詢問。

+3

如果'destination'不是四個主要方向之一?例如。如果它是「移動」的組合? – luqui

+3

爲什麼用移動的結果而不是選定的方向來表示動作,這將允許您進行模式匹配? –

+0

@ Li-yaoXia這正是我想要做的,但是我現在傳遞給函數的是已經部分應用的函數,比如'move East'。這是我試圖模式匹配,但我不知道「解壓」這些值的語法 –

回答

0

Cost需要CoordAction。但是,由於行動需要協調和方向,範圍沒有方向,所以你不能實際使用行動。您需要將該動作應用到座標的某個方向才能獲得一個值。所以mazeCost的唯一實現是那些完全忽略動作的實現,這不是你想要的。

但是,如果您有某種方式的範圍方向,那麼您可以將其應用於該操作(以及座標)。一種做法是通過咖啡。功能Direction -> Cost是一個函數,它爲該方向帶來一個方向並給出一個成本函數

mazeCost :: Direction -> Cost 
mazeCost dir coord act = case act coord dir of 
    Just (x', y') -> 0 -- or whatever the cost is 
    Nothing -> 0 -- or whatever the cost is 

我認爲這是的想法,部分應用程序類似於引入封閉件的很好的例子:mazeCost East是封閉在DirectionEast並給出了該方向的Cost的功能。

我也應該注意到,我沒有看到你提出的解決方案如何可以檢測。如果您沒有指定type Action = Coord -> Direction -> Maybe Coord,則表達式action coordDirection -> Maybe Coord類型的函數,而不是「目標」。如果我誤解了它,並且確實是類型檢查,那麼它仍然是一個部分函數,​​如果該操作不等於Direction之一中的簡單move,則會導致運行時錯誤,正如luqui暗示的那樣。

+0

您對代碼完全正確,它不是類型檢查,因爲我嘗試創建最小示例時犯了一個錯誤;我編輯了這個問題來糾正它。例如,一個動作就是'向南移動',這就是傳遞給'mazeCost'的東西;有沒有辦法「解開」這個參數,這樣我就可以模式匹配或以某種方式評估「方向」? –

1

就快,你只需要ViewPatterns

{-# LANGUAGE ViewPatterns ... #-} 
... 
move ((x,y), d) = ... Just (d,...) ... 

moveCost = curry moveCost' where 
    moveCost' (move -> Just (East, (x,y))) = ... 
    moveCost' (move -> Just (West, (x,y))) = ... 

請注意,我們改變了move類型在這裏。視圖模式只能用單個參數函數返回一個我們可以匹配的模式,所以它必須通過((x,y),d)作爲一個元組,這意味着moveCost'必須接受一個元組,但是我們可以用一個包裝函數來壓縮它。

+0

我看不出如何工作。 'move'不會給出'Maybe Direction'。 –

+0

我們可以對初始方向返回的座標進行元組化,這只是一個簡單的例子,但我會將其添加進去。 –