我正在尝试将foldp与结合两个信号的输入函数的结果一起使用。

这是我的代码。

import Graphics.Element (..)
import Graphics.Collage (..)
import Color (..)
import Signal
import Keyboard
import Text (asText)
import Time (..)

-- Display
render : (Int, Int) -> Element
render (xDiff, yDiff) = collage 200 200 [
                          rotate (degrees (toFloat yDiff))
                          (filled blue (ngon 5 (10 * toFloat xDiff))) ]

-- Combine two signals to be a pair
input = Signal.map2 (,) (fps 25) Keyboard.arrows

-- Fold past combined signals from input and pass resulting signal to render
main : Signal Element
main = Signal.map render
           (Signal.foldp (\dir (upd, {x, y}) ->
                        (x + dir.x, y + dir.y)) (0,0) input)

-- Fold past Keyboard.arrows and pass resulting signal to render
--main : Signal Element
--main = Signal.map render
--           (Signal.foldp (\dir (x, y) ->
--                        (x + dir.x, y + dir.y)) (0,0) Keyboard.arrows)


我得到的错误是:

Type mismatch between the following types on line 34, column 55 to 60:
       (Float, { x : Int, y : Int })

       { a |   x : Int, y : number }

   It is related to the following expression:

       input

Type mismatch between the following types on line 34, column 26 to 46:

       { a |   x : Int, y : number }

       number

   Looks like something besides an Int or Float is being used as a number.
   It is related to the following expression:

       (x + dir.x,y + dir.y)

Type mismatch between the following types on line 34, column 26 to 46:

       Int

       { a |   x : number, y : number }

   It is related to the following expression:

       (x + dir.x,y + dir.y)`


在主要方面,我可以用asText替换render并得到类似的错误,因此我认为即使渲染处理输入可能存在问题,我也认为我与foldp一起使用的功能也存在问题。

最佳答案

TL; DR

这是main的正确代码:

main : Signal Element
main = Signal.map render
           (Signal.foldp (\(upd, dir) (x, y) ->
                        (x + dir.x, y + dir.y)) (0,0) input)


寻找解决方案

您的类型有问题。因此,让我们看一些类型:

foldp : (a -> b -> b) -> b -> Signal a -> Signal b
input : Signal (Float, {x : Int, y : Int})
render : (Int, Int) -> Element
main : Signal Element


main的定义内,问题似乎源于foldp,因此让我们在foldp的上下文中使main的类型更具体。 render映射到输出上,因此b应该是(Int, Int),它与(0,0)初始值相对应。 a应该类似于输入。因此,对于main中的特定foldp,您具有:

foldp :  ((Float, {x : Int, y : Int}) -> (Int, Int) -> (Int, Int)) -- the function
      -> (Int, Int) -- the initial value
      -> Signal (Float, {x : Int, y : Int}) -- the input
      -> Signal (Int, Int) -- the output


好的,所以我们知道foldp的函数参数应该具有哪种类型。但是当前函数有什么错误类型?

(\dir (upd, {x, y}) -> (x + dir.x, y + dir.y)) : {recordExt1 | x : number, y : number'} -> (something, {recordExt2 | x : number, y : number'}) -> (number, number')


嗯..看起来太复杂了。让我们简化一些假设。
*我们可能不需要扩展记录,因此请使用recordExt1 = recordExt2 = {}
*两个number可能是Int
* something是具有xy记录的元组中的第一个,因此必须是Float信号中的input

-- simplified type of inline function
{ x : Int, y : Int} -> (Float, { x : Int, y : Int}) -> (Int, Int)
-- function deduced from specialised `foldp` type
(Float, {x : Int, y : Int}) -> (Int, Int) -> (Int, Int)


那些看起来相似。该函数的第一个和第二个参数已交换,第二个参数应为整数的元组,而不是具有整数xy的记录。

回顾

您可以看到注释中main的另一个定义如何起作用,但是随后您将(x,y)更改为{x,y},并在错误的参数周围添加了(upd, ... )

最后一点

如果您实际上并未计划使用fps 25中的时间增量,则还可以使用:

input = Signal.sampleOn (fps 25) Keyboard.arrows

main = Signal.map render
       (Signal.foldp (\dir (x, y) ->
                    (x + dir.x, y + dir.y)) (0,0) input)


这给您几乎相同的行为。

08-25 23:29