部分应用函数并在之后组合它们

Partially applying Functions and composing them afterwards

我目前正在 Haskell 研究国际象棋游戏。这是我的函数,当您为它提供正确的参数以在王翼进行易位时,它的计算结果为 True。 (问题在第 1 部分和第 2 部分,请查看评论)。我尝试使用函数组合来找到更简洁的解决方案,但它对我来说并没有真正奏效。如果有人能看一眼我所做的并解释我哪里出错了,我会很高兴......提前非常感谢

shortCastlingWhite :: Int -> Int -> GameState -> Bool
shortCastlingWhite start end state@(board,_) = 
(board !! 95 == 10) &&                              -- on 95=(e,1) is a white King
(board !! 98 == 11) &&                              -- on 98=(h,8) is a white Rook
(start == 95 && end == 97) &&                       -- move from (e,1) to 97=(g,1)
(not $ (wasMoved state 95 || wasMoved state 98) &&  -- King and Tower weren't moved until now
(not $ (indexOccupied 96 state ||                       -- part 1 !! 96=(f,1) and (g,1) are unoccupied
(indexOccupied 97 state) ||                         -- part 1
(isThreatenedBy Black 95 state) ||                  -- part 2 !! neither (e,1) nor (f,1) or (g,1) are threatened by Black Figures
(isThreatenedBy Black 96 state) ||                  -- part 2
(isThreatenedBy Black 97 state)))                   -- part 2

这里是所用函数的类型签名

isThreatenedBy :: Colour -> GameState -> Int -> Bool
wasMoved :: GameState -> Int -> Bool

我想将非常冗长的第 1 部分和第 2 部分重写为:

all (swap indexUnoccupied state) [96,97] && 
(all ((not.isThreatenedBy) Black state) [95,96,97]) && 
(all ((not.wasMoved) state) [95,98])  
    where swap f a b = f b a
--

但我无法绕过 :

的错误消息
newchess.hs:240:181:
    Couldn't match expected type `GameState -> a0 -> Bool`
                with actual type `Bool`
    The function `not . isThreatenedBy` is applied to two arguments,
    but its type `Colour -> Bool` has only one
    In the first argument of `all`, namely
      `((not . isThreatenedBy) Black state)`
    In the first argument of `(&&)', namely
    `(all ((not . isThreatenedBy) Black state) [95, 96, 97])`

isThreatenedBy :: Color -> GameState -> Int -> Bool

当我不作曲并且 isThreatenedBy 我应该得到

类型的函数 f = (not . isThreatenedBy)

f :: Colour -> GameState -> Int -> Bool

但我想我确实得到了类似 Colour -> Bool 的东西。 然后我用 Color 和 GameState 的值部分地应用它 结果函数 f' 的类型应该是

f' :: Int -> Bool

然后我将它映射到列表 [95,96,97] 上看看 如果每个元素通过 all

满足 f'

计划大概是这样...

newchess.hs:240:186:
    Couldn't match type `GameState -> Int -> Bool` with `Bool`
    Expected type: Colour -> Bool
      Actual type: Colour -> GameState -> Int -> Bool
    Probable cause: `isThreatenedBy` is applied to too few arguments
    In the second argument of `(.)`, namely `isThreatenedBy`
    In the expression: not . isThreatenedBy

奇怪的是 (not .wasMoved) 在 error1 中被应用到太多参数 可能在错误 2 中太少了,但是 我不能移动括号内的列表元素, 否则我可以回到我开始的那个点

newchess.hs:240:238:
    Couldn't match expected type `a1 -> Bool` with actual type `Bool`
    Possible cause: `not . wasMoved` is applied to too many arguments
    In the first argument of `all`, namely `((not . wasMoved) state)`
    In the second argument of `(&&)`, namely
      `(all ((not . wasMoved) state) [95, 98])`

与上面的错误 1 ​​相同(只是这次使用了 wasMoved)

newchess.hs:240:243:
    Couldn't match type `Int -> Bool' with `Bool`
    Expected type: GameState -> Bool
      Actual type: GameState -> Int -> Bool
    Probable cause: `wasMoved` is applied to too few arguments
    In the second argument of `(.)`, namely `wasMoved`
    In the expression: not . wasMoved
Failed, modules loaded: none.

如我认为的错误 2

我可能对这个有点误解,但是看看这个。这不起作用:

Prelude> let f = (abs . (+))

<interactive>:11:5:
    Non type-variable argument in the constraint: Num (a -> a)
    (Use FlexibleContexts to permit this)
    When checking that ‘f’ has the inferred type
      f :: forall a. (Num a, Num (a -> a)) => a -> a -> a

它不进行类型检查。原因是 (.) 函数接受两个函数作为参数,这两个函数各接受一个参数。在这个例子中,(+) 函数有两个参数,因此是错误的类型。这有效:

Prelude> let f = (abs . (+ 3))

因为我把函数变成了只接受一个参数的函数。您的 isThreatenedBy 函数可以用同样的方式更改:

(all (not . (isThreatenedBy Black state)) [95,96,97])

不确定这是否真的是您的根本问题,但请尝试一下。

让我们从自定义谓词开始:

isThreatenedBy :: Colour -> State -> Position -> Bool

我们当然可以这样写:

isThreatenedBy :: Colour -> (State -> (Position -> Bool))

现在应该清楚为什么这个函数不能和​​not组合了,它本身就是Bool -> Bool:

(.) :: (b -> c) -> (a -> b) -> a -> c

现在替换:

:: not . isThreatenedBy

-- from `not`:
b ~ Bool
c ~ Bool 

-- from `isThreatenedBy:
a ~ Colour
b ~ (State -> (Position -> Bool))

显然 b 与此处不匹配。


现在你可以做的是将组合推到第一个应用程序之外(dvaergiller 在他的回答中所做的),或者引入额外的步骤:

all . map not . map (isThreatenedBy color state) $ [95,96,97]

这可能与典型的 map-reduce 模式形成对比,但我个人认为它更具可读性。


或者,以下的助手:

none = and . map not

(或者,如@FrerichRaabe 所建议并由 Augustus De Morgan 慷慨提供):

none = not . or

可以使这个更清楚。