我是Elm的新手(版本0.19
。
困扰我的是我传递的大量参数。我认为问题是由于我的OOP思维方式造成的。在我的代码中,我有一堆帮助程序函数,需要访问我的model
(TEA)。我一直在视图函数中使用let / in
语法定义这些帮助器,因为这使他们可以访问模型参数。但是,我有10多个辅助函数,而且我一直在不断传递它们,这使我的代码看起来难看且难以理解。在OOP中,这些帮助器函数全都是我将通过的对象上的方法。
下面的代码段是使用elm-ui的伪造示例。完整示例可以在Ellie
上运行Element.layout []
<| column
[ w |> px |> width
, h |> px |> height
, blueBg
, centerX
, centerY
]
[ el [centerX, centerY, whiteTxt, fontSize 40] <| text "Hello world"
, header w h scale whiteTxt space blueBg pad radius whiteBg fontSize blackTxt greyBg blueTxt
]
header w h scale whiteTxt space blueBg pad radius whiteBg fontSize blackTxt greyBg blueTxt =
-- code here
el [] Element.none
什么是最好的方法?
为此,有几种策略:
在标题示例中,您可以提供自己的样式,标题和副标题类型:
type alias Title = String
type alias SubTitle = String
header : HeaderStyle -> Title -> SubTitle -> Element Msg
当您确实有很多信息要传递时,记录通常是保存数据的第一个目标。例如,如果您使用不同的样式多次重复使用header函数,那么HeaderStyle记录类型可能会很有用:
type alias HeaderStyle = { borderColor : Color
, textColor: Color
, backgroundColor : Color
...
}
现在,由于标题和副标题是标题的一部分,您还可以将它们全部拉入一条记录:
type alias HeaderData = { borderColor : Color
, textColor: Color
, backgroundColor : Color
, bannerText : String
, bannerImage : Url
, headerTitle : Title
, headerSubTitle : SubTitle
...
}
如果我们注意库提供的类型,我们可以看到,对于elm-ui,将样式保留在列表中以匹配其类型可能更有意义。修改记录,我们得到:
type alias HeaderData = { styleList : List (Attribute Msg)
, headerTitle : Title
, headerSubTitle : SubTitle
...
}
这里的优点是,我们可以通过调用自动函数styleList: HeaderData -> List (Attribute Msg)
来提取样式列表并直接从Element模块的函数中使用它。
缺点是,如果有人使HeaderData缺少某些键样式,我们将丢失漂亮的编译器错误消息。
无论哪种方式,现在我们的标头函数都只能使用一个输入。
header : HeaderData -> Element Msg
很好,但这仍然意味着,每次运行标头时,我们都需要填充HeaderData。我们如何简化呢?
一种策略是在顶层使用常量,并使用辅助函数/部分应用程序来应用这些常量。
例如,我们可以定义顶级常量和帮助函数,使我们可以创建各种预定义的标头:
pageStyle : List (Attribute Msg)
pageStyle = [ Border.color <| rgb255 35 97 146
, Font.color <| rgb255 35 97 146 ]
redHeaderStyle : Title -> HeaderData
redHeaderStyle title =
{ styleList : pageStyle
++ [ Background.color red
, Font.color black
...
]
, headerTitle : title
}
这里pageStyle可以在其他地方使用,为此特定情况,将readHeaderStyle添加到其中。请注意,我们在后面留了一个参数,因为标题可能会因每个应用程序而异。
当然,在Elm中,您不仅限于列表和记录-您还可以将产品和总和类型用于Header。何时使用每种类型将取决于诸如您希望在何处使用类型安全性以及如何组成函数的事情。
所以总结一下:
首先使用类型对问题域进行建模,而不是根据对象或组件进行思考。
请勿尝试使所有内容通用且可重用。而是创建保存信息的类型并使用辅助函数,因此您只需要担心相关的内容。
不要害怕在顶层定义常量和辅助函数。将let..in
构造的使用限制为提高可读性,而不是像使用方法一样对定义进行分组。
根据需要为您的类型编写辅助函数,而不是尝试创建包含所有可能功能的库。
如果要分隔相似的功能和类型,可以使用模块,然后将其限定为方便的名称。这样您可以说Background.color
和Element.row
。
最后,Scott Wlashchin对函数式编程中的设计策略进行了很好的演讲:Functional programming design patterns by Scott Wlaschin