4

2 つの信号を結合する入力関数の結果で 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)`

主にrenderをasTextに置き換えて同様のエラーが発生する可能性があるため、render処理入力に問題がある可能性がありますが、foldpで使用している関数にも問題があると思います.

4

2 に答える 2

3

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のタイプをより具体的にしましょう。は出力にマッピングされるため、初期値に対応する である必要があります。入力のようにする必要があります。したがって、メインの特定の場合は次のとおりです。foldpmainrenderb(Int, Int)(0,0)afoldp

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 = {}. * 2 つnumberの s は s の可能性がありIntます。x* something は、 andのレコードを持つタプルの最初のものであるため、シグナルのfromyである必要があります。Floatinput

-- 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)

それらは似ています。関数の 1 番目と 2 番目の引数は入れ替わり、2 番目の引数は整数xとのレコードではなく、整数のタプルにする必要がありyます。

回想

mainコメント内の他の定義がどのように機能していたかを見ることができますが、間違った引数の周りに(x,y)toを変更して...{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)

これにより、ほぼ同じ動作が得られます。

于 2015-01-05T19:25:22.763 に答える
1

Apanatshka の優れた回答があっても、 update 関数が から呼び出されたときの引数の交換に混乱していたfoldpので、明確にするためにマイナーな記事を以下に示します。

module Foldp2 where

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))) ]

-- `input` produces a (Float, Record)-Tuple wrapped in a Signal
input : Signal (Float, {x : Int, y : Int})
input = Signal.map2 (,) (fps 25) Keyboard.arrows

-- define an update function operating on the unwrapped `input` function
-- `foldp` will make it work on the wrapped `input'
update : ( Float, {x:Int, y:Int}) -> (Int, Int) -> (Int, Int)
update (upd, dir) (x,y) = (x + dir.x, y + dir.y)

-- Making the type of 'foldp' applied to 'update' explicit:
-- Notice that the order of arguments compared to `update` is swapped.
-- The swapping, I think, was the origin of confusion for OP (mine indeed it was).
folding : (Int, Int) -> Signal (Float, {x:Int, y:Int}) -> Signal (Int, Int)
folding = Signal.foldp update

-- Further notice that "aligning" the arguments in `update` with those of
-- `folding` by:

-- update : (Int, Int) -> ( Float, {x:Int, y:Int}) -> (Int, Int)
-- update (x,y) (upd, dir) = (x + dir.x, y + dir.y)

-- gives error:

-- Type mismatch between the following types on line 26, column 28 to 48:
--        { x : Int, y : Int }
--        number
--    It is related to the following expression:
--        (x + dir.x,y + dir.y) 

-- unless you `flip` the order arguments in `folding`:

-- folding : (Int, Int) -> Signal (Float, {x:Int, y:Int}) -> Signal (Int, Int)
-- folding = Signal.foldp (flip update)

main : Signal Element
main = Signal.map render (folding (0,0) input)
于 2015-03-22T21:08:31.743 に答える