2017-11-24 9 views
1

Elixir에서는 Enum.each 함수를 사용하여 목록의 값을 하나씩 인쇄 할 수 있습니다.Enum.each와 목록 이해의 차이.

a = [1, 2, 3] 
Enum.each(a, fn(x) -> IO.puts x end) 

출력은 다음과 같은 작업을 수행하는 지능형리스트를 사용

1 
2 
3 
:ok 

:

a = [1, 2, 3] 
for x <- a, do: IO.puts x 

출력은 :

1 
2 
3 
[:ok, :ok, :ok] 

의 끝에 출력, Enum.each 함수는 다음 중 하나를 반환합니다. ok, list c omprehension은 3을 반환합니다 : ok. 두 가지 접근 방식의 차이점은 무엇입니까? 이 멍청한 질문에 사과드립니다. 나는 공식적인 엘릭서 의사를 읽었다. 그러나 답을 찾지 못했습니다.

답변

6

올바른 대답이 문제의 핵심을 다루는 것은 아니지만 지금까지는 답변이 제공됩니다. 문제의 핵심은 후드 아래에서 Enum.each, Enum.map, for x <- a 등을 구현하는 방법에 익숙하지 않다는 것입니다. 후드

Enum.map 두 입력 받아 재귀 함수 뿐이다 :

  1. 목록
  2. 그 목록 내의 각 소자에인가해야하는 기능을

이 재귀 함수의 반환 값은 새로운 목록입니다.

더욱를 명확히하기 위해 :

defmodule MyEnum do 
    def map(list, fun) do 
    if Enum.empty?(list) do 
     []        # Null case reached, stop recursing. 
    else 
     [head | tail] = list    # obtain the first element in the list, assign that value to `head`. Store the remaining list inside the variable `tail` 
     projected_value = fun.(head)  # This is where your function gets applied 
     [ projected_value | map(tail, fun)] # Recurse 
    end 
    end 
end 

: fn e -> e * 2 end 다음 새 목록 [2, 4, 6, 8]

Enum.map 간단하게 다음과 같이 구현 될 수를 얻을 것이다 : 당신이 입력으로 목록 [1, 2, 3, 4]과 기능을 갖고 있다고 따라서 MyEnum.map([1,2,3], fn e -> e * 2 end)은 목록을 반환합니다 : [2, 4, 6]

이제 fu 여기서 IO.puts/2과 같이 : MyEnum.map([1,2,3], fn e -> IO.puts(e) end), 변수 projected_value은 결국 IO.puts/2의 반환 값이됩니다. 값을 화면에 인쇄하고 :ok 원자를 반환합니다.

즉,이 경우 작성한 목록은 각각의 새로운 재귀에 대해 원자 :ok을 누적한다는 의미입니다.

이해력이있는 for x <- a은 Enum.map과 비슷하지만 제공된 함수를 목록의 각 요소에 적용하는 재귀 함수이지만 다른 구문을 사용합니다.

Enum.each도 후드 아래의 재귀 함수이지만, 모든 요소를 ​​반복하므로 처리 중에 아무 것도 축적하지 않습니다. 당신이 볼 수 있듯이,이 함수는 항상 :ok을 반환하고 Enum.map 항상 새로운 목록을 반환합니다

defmodule MyEnum do 
    def each(list, fun) do 
    if Enum.empty?(list) do 
     :ok       # Return `:ok` to communicate the entire list has been traversed 
    else 
     [head | tail] = list 
     fun.(head)     # Only apply the function to the element of the list, and do not care about its return value 
     each(tail, fun)    # Continue to traverse the list recursively 
    end 
    end 
end 

: 이것은 당신이 그것을 구현할 수있는 방법이다.

이 모든

때문에, 초등학교 물건입니다 :

  1. 당신은 후드와에서 무슨 일이 일어나고 있는지 이해한다면,
  2. 당신은 본질적으로 Enum.mapfor x <- [1,2,3]는 기본적으로 하나의 단지 다른 인터페이스 모든 질문에 명확히해야한다

|>와 같은 재귀 함수 것으로 알고 있습니다.

또한, 동일한 구조가 Javascript에도 제공됩니다. JS에서 [1,2,3,4].map 또는 [1,2,3,4].each을 수행하는 경우 Elixir과 똑같은 작업을 수행하므로 차이점을 이해하는 데 여전히 문제가있는 경우 먼저 Javascript에서 이러한 구문을보다 명확하게 이해할 수 있습니다.

+1

['IO. inspect/2'] (https://hexdocs.pm/elixir/IO.html#inspect/2)는 전달 된 인수를 반환합니다. ['IO.puts/2'] (https://hexdocs.pm/elixir/IO.html#puts/2)는': ok'를 반환합니다. – mudasobwa

+0

@ mudasobwa 감사합니다. –

+0

@KevinJohnson 자바 스크립트 :'var a = 10; arr = [1, 2, 3, 4, 5]; (i = 0; i <5; ++ i) {a = arr [i] + a} 결과는 다음과 같다. a = 25'The Elixir, a = 10; Enum.each (0..4, fn (x) -> a = arr [i] + a)'이 코드는 오류가 발생합니다. 'for <-0.4, a = Enum.at (arr, i) + a' 이것은 하나의 값이 아닌리스트를 반환합니다. 어떻게하면 자바 스크립트에서와 같은 결과를 얻을 수 있습니까? 고맙습니다 ! – clicli

2

Enum.each/2은 컬렉션에 대해 뭔가를하고 결과에 신경 쓰지 않으려면 잘 맞을 것입니다. :ok은이 함수의 결과로 항상 반환됩니다.

List comprehension은 새로운 컬렉션을 반환합니다.이 컬렉션은 원래의 enumable 객체 (사례 목록)의 각 요소에 대한 함수 호출을 계산 한 결과입니다. Enum.map/2의 대안으로 생각하십시오.

:ok도 각각 IO.puts 호출에 대한 결과이기 때문에 결과가 [:ok, :ok, :ok]입니다. Enum.map/2 이해력이 모두 맵퍼이, 그리고 이해가 어느 정도에서 감속기될 수 있지만 간단히 말해

+0

큰 코드 블록을 실행하고 싶습니다. Enum 일 수 있습니다. 좋은 접근 방식이 아닙니다. 목록의 이해를 시도했지만 javascript와 비교할 때 동일한 결과를 얻지 못했습니다. – clicli

+0

"같은 결과가 아님"은 무엇을 의미합니까? 결과 데이터가 일치하지 않거나 느린가? – fr3dch3n

+0

@ fr3dch3n 필자는 elixir 포럼에서 list comprehension을 for 루프로 사용하여 배웠다. 나는 엘릭서가 기능적 프로그래밍 언어라는 것을 압니다. 어떤 루프도 제공하지 않습니다. 나는 x <- 0..10을 위해 여기에 몇 가지 코드를 사용한다. 그러나 javascript와 비교되는 동일한 결과를 얻지 않았다. for (i = 0; i <11; ++ i) (일부 코드는 여기에서) 엘릭서에서 목록을 얻습니다. 자바 스크립트에서 값을 얻습니다. (링크 : https://elixirforum.com/t/how-to-do-a-for-loop-in-elixir-using-only-recursion/595) – clicli