我正在尝试选择函数式编程,并决定从Project Euler上的问题1开始:基本上将所有小于1000的数字加上3或5整除(链接:a link)。
这是我写的代码。它输出一个3或5的因子列表(仍需要弄清楚如何求和)。
import Html exposing (text)
import Array
main =
text (
toString
[findSum_maxZ 3 5 1000]
)
findSum_maxZ x y max_z =
Array.filter isDivisible_x_or_y (Array.initialize max_z identity)
isDivisible_x_or_y x =
if x % 3 == 0 || x % 5 == 0 then True else False
我的问题是我引用了3和5两次但是我不能用更抽象的'x'和'y'的附加参数调用isDivisible。我的目标是确定删除这些人为可变值的有效方法,以便最终用户只需修改一次输入值。有什么建议吗?
我很抱歉,如果这个问题很愚蠢,没有很多关于ELM的信息(特别是与我使用过的python,c,c ++,java等相比),我仍然对功能编程不太满意行话。任何和所有的帮助表示赞赏。
答案 0 :(得分:5)
关于ML语言的一个很酷的事情是你几乎可以自由地建立自己的“方言”来解决问题。
您可以使用currying仅将x
和y
参数应用于函数,创建一个新函数,其中已经设置了提供的值。
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
let
isDivisibleByX = isDivisible x
isDivisibleByY = isDivisible y
in
Array.initialize maxZ identity
|>Array.filter isDivisibleByX
|>Array.filter isDivisibleByY
--as you can see, it is possible to use a list instead of creating
--new functions, it is up to you to check which abstraction works
--the best
isDivisible a b =
b % a == 0
您也可以使用单一功能,而无需使用currying:
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
Array.initialize maxZ identity
|>Array.filter (\n-> isDivisible x n ) --or just (isDivisible x)
|>Array.filter (\n-> isDivisible y n)
isDivisible a b =
b % a == 0
如果只想用一行过滤数组,可以这样做:
import Html exposing (text)
main = findSum 3 5 1000
|>toString
|>text
findSum x y maxZ =
let
divisibles = \n-> isDivisible x n && isDivisible y n
in
List.range 0 maxZ
|>List.filter divisibles
isDivisible a b =
b % a == 0
答案 1 :(得分:2)
您问题的最直接答案是,您可以isDivisible_x_or_y
取两个因素,然后使用currying将部分应用的函数传递给Array.filter
。
也就是说,您可以像这样定义isDivisible_x_or_y
(我还删除了if True then True else False
语法并直接返回表达式):
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0
Currying是仅向函数提供一些参数的能力,并返回一个接受其余参数的函数。因此,isDivisible_x_or_y
的类型定义为Int -> Int -> Int -> Bool
(即,它需要三个Int
值并返回Bool
)。如果我们提供x
和y
参数的值(例如isDivisible_x_y 3 5
),我们现在会得到一个类型定义为Int -> Bool
的函数。这是Array.filter
预期的类型。
您可以在https://ellie-app.com/sdxWFL9ynka1
看到一个有效的例子另外几个笔记:
List
比榆树中的Array
更常见。如果需要获取特定索引的项目,则只能使用Array
。您可以使用Array.initialize
List.range
使用管道运算符|>
通常可以使您的代码更容易阅读。您拥有text (toString (getValue))
而不是getValue |> toString |> text
,而现在按操作发生的顺序排列,并且没有额外的括号。整个程序可能只是一个简单的管道(在很多情况下,将所有东西都放在一个管道中可能会过多):
main =
List.range 0 max_z
|> List.filter (isDivisible_x_or_y 3 5)
|> toString
|> text
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0