2017-05-27 46 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

我们可以对初始方向返回的坐标进行元组化,这只是一个简单的例子,但我会将其添加进去。 –