【问题标题】:Mysterious Type Mismatch in ElmElm 中的神秘类型不匹配
【发布时间】:2015-02-06 11:53:09
【问题描述】:

下面的代码应该产生一个按钮,当按下它时会创建一个框(以及一个用于移除框的按钮)

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 的,我该如何解决?

【问题讨论】:

    标签: user-interface dictionary types elm


    【解决方案1】:

    TL;DR

    main 中查找并替换带有collage 调用的行:

                                , collage 500 500 (List.map (\((x,y), makebox) -> move (x,y) (toForm makebox))
    

    快速代码清理

    这是很多代码。我不得不稍微改变一下风格才能理解它是如何工作的。我所做的是将更多的函数移到顶层并给它们类型注释。我还将button_add/remove 更改为camelCase,因为这是标准的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' 函数上。我在 cmets 中添加了我想到的类型签名。

    问题

    这段代码有两个问题:

    1. move' 接受 Element(除其他外)并尝试 move 它,但 move 适用于 Forms。所以这需要调用toForm,然后才能工作。
    2. 这是类型错误的来源:Dict.values 给出了值列表,而不是 Just 值列表(Maybe.Maybe 类型)。

    因此,解决方案是move' 函数,如下所示:

    move' : ((Float,Float), Element) -> Form
    move' (a,b) = move a (toForm b)
    

    【讨论】:

    • 感谢您的清理和帮助,但这似乎并没有解决错误 - 只是将其移至第 49 行和第 52 行之间。我不知道如何处理问题 2。跨度>
    • @user22723 你确定吗?我在发布前检查了 TL;DR 解决方案和清理过的解决方案。请注意,上面清理过的代码并不是完整的代码,您需要将 move' 实现替换为我结束答案的那个。这是一个编译版本:share-elm.com/sprout/54d5308ce4b05f9c59b259cc
    • 哦,我的错!我没有换行,哎呀。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 2015-07-27
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多