이 Haskell 코드에서 도트 연산자가 수행하는 작업을 이해하려고합니다.
sumEuler = sum . (map euler) . mkList
전체 소스 코드는 다음과 같습니다.
나의 이해
점 연산자는 두 가지 함수 sum
와 결과 map euler
및 결과를 mkList
입력으로 취합니다 .
하지만 sum
함수가 아니라 함수의 인수 인 거죠? 그래서 여기서 무슨 일이 일어나고 있습니까?
또한 무엇을 (map euler)
하고 있습니까?
암호
mkList :: Int -> [Int]
mkList n = [1..n-1]
euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))
sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
답변
간단히 말해서 .
수학에서와 같이 함수 구성입니다.
f (g x) = (f . g) x
귀하의 경우 sumEuler
다음과 같이 정의 할 수 있는 새 함수를 만들고 있습니다.
sumEuler x = sum (map euler (mkList x))
예제의 스타일은 “점없는”스타일이라고합니다. 함수에 대한 인수는 생략됩니다. 이것은 많은 경우에 더 명확한 코드를 만듭니다. (처음 보는 것은 어렵지만 잠시 후에 익숙해 질 것입니다. 일반적인 Haskell 관용구입니다.)
여전히 혼란 스러우면 .
UNIX 파이프와 같은 것과 관련된 것이 도움이 될 수 있습니다 . 경우 f
의 출력이되고 g
출력이됩니다의 입력 ‘ h
의 입력을, 당신은 같은 명령 행에 그 쓰기 것 f < x | g | h
. Haskell에서는 .
UNIX처럼 작동 |
하지만 “뒤로”- h . g . f $ x
. 이 표기법은 목록을 처리 할 때 매우 유용합니다. 과 같은 다루기 힘든 구조 대신 map (\x -> x * 2 + 10) [1..10]
그냥 쓸 수 있습니다 (+10) . (*2) <$> [1..10]
. (그리고 해당 함수를 단일 값에만 적용하려면 (+10) . (*2) $ 10
. Consistent입니다!)
Haskell 위키에는 좀 더 자세한 내용이 담긴 좋은 기사가 있습니다 : http://www.haskell.org/haskellwiki/Pointfree
답변
. 연산자는 함수를 구성합니다. 예를 들면
a . b
어디 와 b를 함수는 새로운되어있는 기능 이 다음 인수, b를 실행하는 결과에. 귀하의 코드
sumEuler = sum . (map euler) . mkList
다음과 정확히 동일합니다.
sumEuler myArgument = sum (map euler (mkList myArgument))
하지만 읽기가 더 쉬웠 으면합니다. map euler 주위에 괄호가있는 이유는 sum , map euler 및 mkList – map euler 가 단일 함수 라는 세 가지 함수가 구성되어 있음을 더 명확하게하기 때문 입니다.
답변
sum
에 대한 인수가 아니라 Haskell Prelude의 함수입니다 sumEuler
. 유형이 있습니다
Num a => [a] -> a
함수 구성 연산자 .
에는 유형이 있습니다.
(b -> c) -> (a -> b) -> a -> c
그래서 우리는
euler :: Int -> Int
map :: (a -> b ) -> [a ] -> [b ]
(map euler) :: [Int] -> [Int]
mkList :: Int -> [Int]
(map euler) . mkList :: Int -> [Int]
sum :: Num a => [a ] -> a
sum . (map euler) . mkList :: Int -> Int
참고 Int
참의 인스턴스입니다 Num
typeclass.
답변
. 연산자는 함수 구성에 사용됩니다. 수학과 마찬가지로 f (x) 및 g (x) f 함수가 필요한 경우. g는 f (g (x))가됩니다.
map은 목록에 함수를 적용하는 내장 함수입니다. 함수를 괄호 안에 넣으면 함수가 인수로 처리됩니다. 이것에 대한 용어는 카레 입니다. 당신은 그것을 찾아야합니다.
하는 것은 두 개의 인수가있는 함수를 취하고 인수 오일러를 적용한다는 것입니다. (맵 오일러) 맞죠? 결과는 하나의 인수 만 취하는 새 함수입니다.
합계. (지도 오일러). mkList는 기본적으로이 모든 것을 합치는 멋진 방법입니다. 내 Haskell은 약간 녹슬었지만 마지막 기능을 직접 조합 할 수 있습니까?
답변
Haskell의 점 연산자
이 Haskell 코드에서 도트 연산자가 수행하는 작업을 이해하려고합니다.
sumEuler = sum . (map euler) . mkList
짧은 답변
점이없는 등가 코드, 즉
sumEuler = \x -> sum ((map euler) (mkList x))
또는 람다없이
sumEuler x = sum ((map euler) (mkList x))
점 (.)은 기능 구성을 나타냅니다.
더 긴 답변
먼저 euler
to 의 부분적 적용을 단순화합시다 map
.
map_euler = map euler
sumEuler = sum . map_euler . mkList
이제 우리는 점만 가지고 있습니다. 이 점은 무엇을 나타 냅니까?
에서 소스 :
(.) :: (b -> c) -> (a -> b) -> a -> c (.) f g = \x -> f (g x)
따라서 (.)
는 IS 작성 연산자 .
짓다
수학에서 함수 f (x)와 g (x), 즉 f (g (x))의 구성을 다음과 같이 쓸 수 있습니다.
(f ∘ g) (x)
“g로 구성된 f”로 읽을 수 있습니다.
따라서 Haskell에서 f ∘ g 또는 g로 구성된 f는 다음과 같이 쓸 수 있습니다.
f . g
컴포지션은 연관성이 있습니다. 즉, 컴포지션 연산자로 작성된 f (g (h (x)))는 모호함없이 괄호를 생략 할 수 있습니다.
즉, (f ∘ g) ∘ h는 f ∘ (g ∘ h)와 동일하므로 간단히 f ∘ g ∘ h로 쓸 수 있습니다.
뒤로 돌기
이전 단순화로 돌아 가면 다음과 같습니다.
sumEuler = sum . map_euler . mkList
이는 sumEuler
해당 기능의 적용되지 않은 구성 임을 의미합니다 .
sumEuler = \x -> sum (map_euler (mkList x))
답변
도트 연산자는 왼쪽에있는 함수 ( sum
)를 오른쪽에있는 함수의 출력에 적용합니다. 귀하의 경우에는, 당신은 함께 여러 가지 기능을 체인있어 – 당신의 결과를 전달하는 mkList
에 (map euler)
, 다음에 그 결과를 전달합니다 sum
.
이 사이트 에는 몇 가지 개념에 대한 좋은 소개가 있습니다.