部分应用函数并在之后组合它们
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
可以使这个更清楚。
我目前正在 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
可以使这个更清楚。