Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I refactor this function in ELM?

I am trying to pick up functional programming and decided to start with Problem 1 on Project Euler: basically add all numbers less than 1000 divisible by 3 or 5 (link: a link).

This is the code that I have written. It outputs a list of factors of 3 or 5 (still need to figure out how to sum).

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

My issue is that I reference 3 and 5 twice but I cannot call isDivisible with the additional parameters of the more abstract 'x' and'y'. My goal is to determine effective methods of removing these artificially mutable values so the end user only has to modify each input value once. Any advice?

I apologize if this question is dumb, there is not a lot of information on ELM available (especially compared to python, c, c++, java, etc which I have used) and I am still not fully comfortable with the functional programming jargon. Any and all help is appreciated.

like image 475
Sean Francis Potempa Avatar asked Mar 07 '23 01:03

Sean Francis Potempa


1 Answers

The cool thing about ML languages is that you are pretty much free to build your own "dialect" to solve problems.

You can use currying to apply just the x and y arguments to your function, creating a new function where the supplied values are already set.

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 

You can also work with a single function, without resorting to 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 

If you want to filter the array with just one line, you can do this:

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 
like image 148
lfarroco Avatar answered Mar 29 '23 16:03

lfarroco