Elm 中神秘的类型不匹配
Mysterious Type Mismatch in Elm
下面的代码应该产生一个按钮,当按下它时会创建一个框(以及一个用于移除框的按钮)
import Graphics.Input
import Signal (..)
import Signal
import Mouse
import Text (Text, asText, plainText)
import Graphics.Element (..)
import Graphics.Collage (..)
import Color (..)
import List
import Dict
-- x y id | id
type Event = Add (Float, Float, Int) | Remove (Int) | Maybe
makebox : Int -> Element
makebox id =
let (w, h) = (30, 30)
in flow down
[ layers [plainText "aaaa", collage w h [square 30 |> filled red]]
, button_remove id ]
add = Signal.channel (0,0,0)
remove = Signal.channel (0)
button_add x y = Graphics.Input.button (Signal.send add (x, y, 2)) "add a box"
button_remove id = Graphics.Input.button (Signal.send remove (id)) "remove me"
main =
let update event =
case event of
Add (x, y, id) -> Dict.insert id ((x,y), ((makebox id)))
Remove (id) -> Dict.remove id
Maybe -> identity
in Signal.map (\dict -> flow down
[ button_add 10.0 20.0 --makes add & remove buttons
, collage 500 500 (List.map (\(Just ((x,y), makebox)) -> move (x,y) makebox)
(Dict.values dict)) --draws the dict
]) --map function argument
(foldp update Dict.empty
(merge
(Add <~ (Signal.subscribe add)) --pipes button channels into events
(Remove <~ (Signal.subscribe remove)))) --map signal argument
但是,它会产生这种类型的错误:
Type mismatch between the following types on line 40, column 14 to 20:
((Int, Int))
Maybe.Maybe
It is related to the following expression:
update
我看不出这个错误是从哪里来的,Maybe.Maybe 是从哪里传递到 update
的,我该如何解决它?
TL;DR
查找并替换 main
中 collage
调用的行:
, collage 500 500 (List.map (\((x,y), makebox) -> move (x,y) (toForm makebox))
快速代码清理
代码太多了。我不得不稍微改变一下风格来理解它是如何工作的。我所做的是将更多功能移至顶层并为它们提供类型注释。我还将 button_add
/remove
更改为驼峰式,因为这是标准的 Elm 命名约定。这是结果:
import Graphics.Input
import Signal (..)
import Signal
import Mouse
import Text (Text, asText, plainText)
import Graphics.Element (..)
import Graphics.Collage (..)
import Color (..)
import List
import Dict
-- x y id | id
type Event = Add (Float, Float, Int) | Remove (Int) | Maybe
type alias Model = Dict.Dict Int ((Float,Float), Element)
makebox : Int -> Element
makebox id =
let (w, h) = (30, 30)
in flow down
[ layers [plainText "aaaa", collage w h [square 30 |> filled red]]
, buttonRemove id ]
add : Signal.Channel (Float,Float,Int)
add = Signal.channel (0,0,0)
remove : Signal.Channel Int
remove = Signal.channel 0
buttonAdd : Float -> Float -> Element
buttonAdd x y = Graphics.Input.button (Signal.send add (x, y, 2)) "add a box"
buttonRemove : Int -> Element
buttonRemove id = Graphics.Input.button (Signal.send remove id) "remove me"
update : Event -> Model -> Model
update event =
case event of
Add (x, y, id) -> Dict.insert id ((x,y), makebox id)
Remove (id) -> Dict.remove id
Maybe -> identity
-- move' : Just ((Float,Float),Element) -> Form
move' (Just ((x,y), makebox)) = move (x,y) makebox
view : Model -> Element
view dict =
flow down
[ buttonAdd 10.0 20.0 --makes add & remove buttons
, collage 500 500 (List.map move' (Dict.values dict)) --draws the dict
]
input : Signal Event
input = merge
(Add <~ (Signal.subscribe add)) --pipes button channels into events
(Remove <~ (Signal.subscribe remove))
model : Signal Model
model = foldp update Dict.empty input
main : Signal Element
main = view <~ model
我们仍然得到相同的,不是很有帮助的类型错误。但现在它在 move'
函数上。我在评论中添加了我想到的类型签名。
问题
这段代码有两个问题:
move'
接受一个 Element
(除其他外)并尝试 move
它,但 move
对 Form
起作用。所以这需要调用 toForm
,然后才能工作。
- 这是类型错误的来源:
Dict.values
给出了值列表,而不是 Just
值列表(Maybe.Maybe
类型)。
因此,解决方案是一个 move'
函数,如下所示:
move' : ((Float,Float), Element) -> Form
move' (a,b) = move a (toForm b)
下面的代码应该产生一个按钮,当按下它时会创建一个框(以及一个用于移除框的按钮)
import Graphics.Input
import Signal (..)
import Signal
import Mouse
import Text (Text, asText, plainText)
import Graphics.Element (..)
import Graphics.Collage (..)
import Color (..)
import List
import Dict
-- x y id | id
type Event = Add (Float, Float, Int) | Remove (Int) | Maybe
makebox : Int -> Element
makebox id =
let (w, h) = (30, 30)
in flow down
[ layers [plainText "aaaa", collage w h [square 30 |> filled red]]
, button_remove id ]
add = Signal.channel (0,0,0)
remove = Signal.channel (0)
button_add x y = Graphics.Input.button (Signal.send add (x, y, 2)) "add a box"
button_remove id = Graphics.Input.button (Signal.send remove (id)) "remove me"
main =
let update event =
case event of
Add (x, y, id) -> Dict.insert id ((x,y), ((makebox id)))
Remove (id) -> Dict.remove id
Maybe -> identity
in Signal.map (\dict -> flow down
[ button_add 10.0 20.0 --makes add & remove buttons
, collage 500 500 (List.map (\(Just ((x,y), makebox)) -> move (x,y) makebox)
(Dict.values dict)) --draws the dict
]) --map function argument
(foldp update Dict.empty
(merge
(Add <~ (Signal.subscribe add)) --pipes button channels into events
(Remove <~ (Signal.subscribe remove)))) --map signal argument
但是,它会产生这种类型的错误:
Type mismatch between the following types on line 40, column 14 to 20:
((Int, Int))
Maybe.Maybe
It is related to the following expression:
update
我看不出这个错误是从哪里来的,Maybe.Maybe 是从哪里传递到 update
的,我该如何解决它?
TL;DR
查找并替换 main
中 collage
调用的行:
, collage 500 500 (List.map (\((x,y), makebox) -> move (x,y) (toForm makebox))
快速代码清理
代码太多了。我不得不稍微改变一下风格来理解它是如何工作的。我所做的是将更多功能移至顶层并为它们提供类型注释。我还将 button_add
/remove
更改为驼峰式,因为这是标准的 Elm 命名约定。这是结果:
import Graphics.Input
import Signal (..)
import Signal
import Mouse
import Text (Text, asText, plainText)
import Graphics.Element (..)
import Graphics.Collage (..)
import Color (..)
import List
import Dict
-- x y id | id
type Event = Add (Float, Float, Int) | Remove (Int) | Maybe
type alias Model = Dict.Dict Int ((Float,Float), Element)
makebox : Int -> Element
makebox id =
let (w, h) = (30, 30)
in flow down
[ layers [plainText "aaaa", collage w h [square 30 |> filled red]]
, buttonRemove id ]
add : Signal.Channel (Float,Float,Int)
add = Signal.channel (0,0,0)
remove : Signal.Channel Int
remove = Signal.channel 0
buttonAdd : Float -> Float -> Element
buttonAdd x y = Graphics.Input.button (Signal.send add (x, y, 2)) "add a box"
buttonRemove : Int -> Element
buttonRemove id = Graphics.Input.button (Signal.send remove id) "remove me"
update : Event -> Model -> Model
update event =
case event of
Add (x, y, id) -> Dict.insert id ((x,y), makebox id)
Remove (id) -> Dict.remove id
Maybe -> identity
-- move' : Just ((Float,Float),Element) -> Form
move' (Just ((x,y), makebox)) = move (x,y) makebox
view : Model -> Element
view dict =
flow down
[ buttonAdd 10.0 20.0 --makes add & remove buttons
, collage 500 500 (List.map move' (Dict.values dict)) --draws the dict
]
input : Signal Event
input = merge
(Add <~ (Signal.subscribe add)) --pipes button channels into events
(Remove <~ (Signal.subscribe remove))
model : Signal Model
model = foldp update Dict.empty input
main : Signal Element
main = view <~ model
我们仍然得到相同的,不是很有帮助的类型错误。但现在它在 move'
函数上。我在评论中添加了我想到的类型签名。
问题
这段代码有两个问题:
move'
接受一个Element
(除其他外)并尝试move
它,但move
对Form
起作用。所以这需要调用toForm
,然后才能工作。- 这是类型错误的来源:
Dict.values
给出了值列表,而不是Just
值列表(Maybe.Maybe
类型)。
因此,解决方案是一个 move'
函数,如下所示:
move' : ((Float,Float), Element) -> Form
move' (a,b) = move a (toForm b)