【问题标题】:Currying (partial function) in custom event listener自定义事件侦听器中的柯里化(部分函数)
【发布时间】:2017-04-04 13:29:02
【问题描述】:

这是简短的版本:

我有一个函数:

onClick : String -> Bool -> (State -> msg) -> Options.Property c msg
onClick name isReversed toMsg =
    Options.on "click" <| Json.succeed <|
    toMsg (State name isReversed)

我想把函数改成这样:

onClick : String -> Bool -> (State -> msg) -> (Maybe msg -> Options.Property c msg)

换句话说,我希望它返回一个接受可能消息的部分函数。但是,我不知道该怎么做!帮助将不胜感激。

这是长版:

我正在尝试构建 elm 可排序表包的“分支”,它使用 elm mdl 包并允许在列标题上自定义事件侦听器。可排序表包(显然)在按该列对表进行排序的列标题上应用事件侦听器。

不幸的是,您不能在同一个元素上拥有两个“onClick”侦听器,因此我决定将自定义消息作为参数传递给排序消息,然后将其作为命令发送排序更新。抱歉,如果您不熟悉该软件包并且这一切听起来都像是胡言乱语,我只是想为我的问题提供上下文。

可排序表包的开发人员创建了一个自定义事件侦听器,如下所示:

onClick : String -> Bool -> (State -> msg) -> Attribute msg
onClick name isReversed toMsg =
  E.on "click" <| Json.map toMsg <|
    Json.map2 State (Json.succeed name) (Json.succeed isReversed)

我已经对其进行了一些更改以使用 mdl 自定义事件侦听器并使其(在我看来)更具可读性:

onClick : String -> Bool -> (State -> msg) -> Options.Property c msg
onClick name isReversed toMsg =
    Options.on "click" <| Json.succeed <|
    toMsg (State name isReversed)

正如我所说,我希望它是这样的:

onClick : String -> Bool -> (State -> msg) -> (Maybe msg -> Options.Property c msg)

但是,如果您熟悉该软件包并且对单击列时使用自定义消息有任何其他建议,请提出建议!我真的不知道我在做什么。

更长的版本:

在组件的视图代码中,有一个变量theadDetails,如下所示:

theadDetails = 
customizations.thead (List.map (toHeaderInfo state toMsg columns)

state toMsgcolumns 都来自项目主视图代码中的配置。 toMsg 是在主更新中处理的消息(组件不跟踪自己的状态)。

toHeaderInfo 看起来像这样:

toHeaderInfo : State -> (State -> msg) -> ColumnData data msg -> ( String, Status, Options.Property c msg )
toHeaderInfo (State sortName isReversed) toMsg { name, sorter } =
    case sorter of
        None ->
            ( name, Unsortable, onClick sortName isReversed toMsg )

        Decreasing _ ->
            ( name, Sortable (name == sortName), onClick name False toMsg )

        IncOrDec _ ->
            if name == sortName then
                ( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
            else
                ( name, Reversible Nothing, onClick name False toMsg )

这基本上是呈现每个元素中包含的数据的地方。所有关于Statesorter 的内容都与每列的排序配置方式和当前顺序有关。但是你看,这里onClick 被调用并传递了所需的参数。

正如您在 theadDetails 中看到的,此信息随后被传递给函数 customizations.tHead,如下所示:

defaultCustomizations : Customizations data msg c
defaultCustomizations =
    { tableAttrs = []
    , caption = Nothing
    , thead = simpleThead
    , tfoot = Nothing
    , tbodyAttrs = []
    , rowAttrs = simpleRowAttrs
    }


simpleThead : List ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> HtmlDetails {} msg
simpleThead headers =
    HtmlDetails [] (List.map simpleTheadHelp headers)


simpleTheadHelp : ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> Html msg
simpleTheadHelp ( name, status, onClick ) =
    let
        check =
            Debug.log "status" status

        attrs =
            case status of
                Unsortable ->
                    []

                Sortable selected ->
                    if selected then
                        [ onClick
                        , Options.css "color" "rgb(0,0,0)"
                        ]
                    else
                        [ onClick ]

                Reversible Nothing ->
                    [ onClick
                    ]

                Reversible (Just isReversed) ->
                    [ onClick
                    , Options.css "color" "rgb(0,0,0)"
                    ]
    in
        Table.th attrs [ Html.text name ]

正是在这里我想传递最后一个论点。所以 simpleTheadHeald 会变成:

simpleTheadHelp : ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> Html msg
simpleTheadHelp ( name, status, onClick ) =
    let
        check =
            Debug.log "status" status

        attrs =
            case status of
                Unsortable ->
                    []

                Sortable selected ->
                    if selected then
                        [ onClick Nothing
                        , Options.css "color" "rgb(0,0,0)"
                        ]
                    else
                        [ onClick Nothing ]

                Reversible Nothing ->
                    [ onClick Nothing
                    ]

                Reversible (Just isReversed) ->
                    [ onClick Nothing
                    , Options.css "color" "rgb(0,0,0)"
                    ]
    in
        Table.th attrs [ Html.text name ]

然而,这给了我一个错误,说 onClick 不是一个函数(因为在类型定义中它不期望一个参数)。

对不起,我解释得这么糟糕!我真的很想在我去的时候弄清楚,所以我很感激你的耐心。

【问题讨论】:

    标签: elm


    【解决方案1】:

    我不熟悉这个包,所以如果我在你的问题中遗漏了什么或者告诉你一些你已经知道的东西,我很抱歉。

    Elm 中的函数是自动柯里化的。您需要做的就是向函数传递一组不完整的参数,然后您将返回一个接受剩余参数的函数。所以这将是你的函数签名:

    onClick : String -> Bool -> (State -> msg) -> Maybe msg -> Options.Property c msg
    onClick name isReversed toMsg maybeMsg =
    

    然后您编写函数,使用所有参数,根本不用担心偏应用。仅使用前三个参数调用该函数,如下所示:

    onClick "myName" True MyMsg
    

    会自动返回一个带有这个签名的函数:

    newFunction : Maybe msg -> Options.Property c msg
    

    你不需要做任何其他事情。

    【讨论】:

    • 谢谢!这似乎成功了。哎呀,我在尝试各种疯狂的事情,很高兴知道它是如此简单。
    猜你喜欢
    • 2022-08-14
    • 1970-01-01
    • 2012-03-14
    • 2012-12-27
    • 2013-03-08
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多