1

来自 Elm 新手但长期使用 Haskeller,快速查询。

目的:有一张地图,上面有城镇的指定位置,我想检查用户点击是否靠近城镇,并识别出那个城镇。

所以,我像往常一样收集信号:

clickPositionsSignal = sampleOn Mouse.clicks Mouse.position

这给了我一个元组,我想把它变成一个 Int (表示最近城镇的编号)。城镇被指定为

positions : [Position] 
type Position = {number : Int, x : Int, y : Int}

这样做的功能是:

whichTown : (Int,Int) -> Int
whichTown (x,y) = 
            let pz = map (\p -> getDistance p.x p.y x y) positions |> head
            in pz.number

现在,我需要将此函数应用于我的 clickPositionsSignal。

环顾各种示例,我修改了一些代码以......

whichLocationSignal : Signal Int
whichLocationSignal =           
      let wbl (x,y) = whichTown(x,y)
      in wbl <~ clickPositionsSignal

....这行得通。我得到最近城镇的号码。

但这是无可救药的麻烦和重复。问题是为什么我不能简单地写:

whichLocationSignal = whichTown clickPositionsSignal

那条线引发了多个类型错误,我还没有足够的经验来解释

4

1 回答 1

1

TL;DR

It should be:

whichLocationSignal = whichTown <~ clickPositionsSignal

or

whichLocationSignal = lift whichTown clickPositionsSignal

(which you already figured out yourself)

How to read the type errors

So a full version of your code that gives these type-errors would be:

import Mouse

type Position = {number : Int, x : Int, y : Int}

clickPositionsSignal : Signal (Int,Int)
clickPositionsSignal = sampleOn Mouse.clicks Mouse.position

positions : [Position]
positions = []

getDistance x1 y1 x2 y2 = { number = 0 }

whichTown : (Int,Int) -> Int
whichTown (x,y) = 
  let pz = map (\p -> getDistance p.x p.y x y) positions |> head
  in pz.number

whichLocationSignal : Signal Int
whichLocationSignal = whichTown clickPositionsSignal

The type errors I then get are:

Type error on line 19, column 33 to 53:
     clickPositionsSignal

  Expected Type: (Int, Int)
    Actual Type: Int

Type error on line 19, column 33 to 53:
     clickPositionsSignal

  Expected Type: Signal.Signal
    Actual Type: (Int)

Type error on line 19, column 23 to 32:
     whichTown

  Expected Type: Int
    Actual Type: Signal.Signal Int

I admit, these type errors are confusing.
(You might even say they are incorrect. All I can say to that is this is the current quality of type errors that you get, sorry!)
One basic tip when a type error from Elm doesn't make sense is to see if it makes more sense when you flip the expected/actual. Then the first type error makes no sense. But the second gives some information: clickPositionsSignal is somehow expected to have a type Int, not some Signal. Together with the third error message this starts to make sense: whichTown does something the other way around where an Int should be given but you get a Signal...
At that point you can find the uses of these two together, and once you note that whichTown works on (Int,Int) and clickPositionsSignal : Signal (Int,Int), you've found your error and the compiler messages make some kind of crooked sense.

The fix as stated above is to use lift : (a -> b) -> Signal a -> Signal b to "lift" the function (whichTown) to the Signal "level". Most people prefer to use the infix operator <~.

于 2014-11-04T09:28:25.697 回答