패턴 (f .) . g
에 따라 정의 된 많은 기능을 보아 왔습니다. 예 :(f.)는 무엇입니까? 하스켈에서의 평균은?
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
이것은 무엇을 의미합니까?
패턴 (f .) . g
에 따라 정의 된 많은 기능을 보아 왔습니다. 예 :(f.)는 무엇입니까? 하스켈에서의 평균은?
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
이것은 무엇을 의미합니까?
도트 연산자 ((.)
)는 function composition 연산자입니다. 당신이 그것을 볼 수 있듯이
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
유형 b -> c
의 기능과 유형 a -> b
의 다른 기능을 소요하고 처음으로 두 번째 함수의 결과를 적용 유형 a -> c
의 기능 (예를 반환합니다 다음과 같이 정의된다 기능).
함수 합성 연산자는 매우 유용합니다. 이 함수를 사용하면 한 함수의 출력을 다른 함수의 입력으로 파이프 할 수 있습니다.
main = interact (\x -> unlines (reverse (lines x)))
을하지 가독성 다음과 같이 예를 들어, 당신은 하스켈에서 tac 프로그램을 작성할 수 있습니다. 다음과 같이 당신이 그것을 쓸 수 있지만 기능 성분을 사용하여 :
main = interact (unlines . reverse . lines)
당신이 함수의 합성을 볼 수 있듯이 매우 유용하지만 당신은 모든 곳에서 사용할 수 없습니다. 예를 들어 사용자가 기능 할 수없는 파이프 조성물을 사용 length
로 filter
출력 : filter
유형의 (a -> Bool) -> [a] -> [a]
때문에
countWhere = length . filter -- this is not allowed
이 허용되지 않는 이유이다. a -> b
과 비교하면 a
은 (a -> Bool)
이고 b
은 [a] -> [a]
입니다. 하스켈은 length
이 b -> c
(즉, ([a] -> [a]) -> c
)이 될 것으로 예상하므로 형식이 일치하지 않습니다. 실제로는 [a] -> Int
유형입니다.
해결책은 아주 간단합니다 :
countWhere f = length . filter f
그러나 어떤 사람들은 그 여분 매달려 f
을 좋아하지 않는다.
countWhere = (length .) . filter
을 그들은이를 얻는 방법 : 그들은 다음과 같이 pointfree 스타일 countWhere
를 작성하는 것을 선호? 고려 :
countWhere f xs = length (filter f xs)
-- But `f x y` is `(f x) y`. Hence:
countWhere f xs = length ((filter f) xs)
-- But `\x -> f (g x)` is `f . g`. Hence:
countWhere f = length . (filter f)
-- But `f . g` is `(f .) g`. Hence:
countWhere f = (length .) (filter f)
-- But `\x -> f (g x)` is `f . g`. Hence:
countWhere = (length .) . filter
당신이 (f .) . g
을 볼 수 있듯이 단순히 \x y -> f (g x y)
입니다. 이 개념은 실제로 반복 될 수 있습니다.
f . g --> \x -> f (g x)
(f .) . g --> \x y -> f (g x y)
((f .) .) . g --> \x y z -> f (g x y z)
(((f .) .) .) . g --> \w x y z -> f (g w x y z)
꽤 좋지는 않지만 끝내줍니다.두 가지 기능을 감안할 때 당신은 또한 당신의 자신의 기능 구성 사업자를 작성할 수 있습니다
f .: g = (f .) . g
f .:: g = ((f .) .) . g
f .::: g = (((f .) .) .) . g
을 대신 다음과 같이 countWhere
을 쓸 수있는 (.:)
연산자를 사용 :
countWhere = length .: filter
을 흥미롭게도이 점 자유로운 스타일로 (.:)
을 쓸 수 있지만 잘 :
f .: g = (f .) . g
-- But `f . g` is `(.) f g`. Hence:
f .: g = (.) (f .) g
-- But `\x -> f x` is `f`. Hence:
(f .:) = (.) (f .)
-- But `(f .)` is `((.) f)`. Hence:
(f .:) = (.) ((.) f)
-- But `\x -> f (g x)` is `f . g`. Hence:
(.:) = (.) . (.)
마찬가지로 우리가 얻을 :
(.::) = (.) . (.) . (.)
(.:::) = (.) . (.) . (.) . (.)
당신이 (.:)
, (.::)
및 (.:::)
이 (.)
의 정당한 권력은 있습니다 볼 수있는 (즉, 그들은 iterated functions의 (.)
입니다). 수학 번호는 : 수학 함수에 대한 유사
x^0 = 1
x^n = x * x^(n - 1)
:
f .^ 0 = id
f .^ n = f . (f .^ (n - 1))
f
경우는 (.)
이다 :이 문서의 끝 부분에 가까운 우리에게 가져다
(.) .^ 1 = (.)
(.) .^ 2 = (.:)
(.) .^ 3 = (.::)
(.) .^ 4 = (.:::)
.
mf = compose map filter
: 당신이 지금과 같이
mf
을 쓸 수
compose f g = (. f) . (.) . g
compose f g = ((. f) . (.)) . g
compose f g = (.) ((. f) . (.)) g
compose f = (.) ((. f) . (.))
compose f = (.) ((. (.)) (. f))
compose f = ((.) . (. (.))) (. f)
compose f = ((.) . (. (.))) (flip (.) f)
compose f = ((.) . (. (.))) ((flip (.)) f)
compose = ((.) . (. (.))) . (flip (.))
compose
을 사용하여 다음과 같이
mf a b c = filter a (map b c)
mf a b c = filter a ((map b) c)
mf a b = filter a . (map b)
mf a b = (filter a .) (map b)
mf a = (filter a .) . map
mf a = (. map) (filter a .)
mf a = (. map) ((filter a) .)
mf a = (. map) ((.) (filter a))
mf a = ((. map) . (.)) (filter a)
mf = ((. map) . (.)) . filter
mf = (. map) . (.) . filter
우리는 더이 문제를 단순화 할 수 있습니다 : 최종 도전의이 pointfree 스타일에 다음 함수를 작성하자
네, 약간 못 생겼지 만 정말 멋진 생각이기도합니다. 이제 \x y z -> f x (g y z)
형식의 함수를 compose f g
으로 쓸 수 있으며 매우 깔끔합니다.
'(.)^i '형식의 표현식은 형식이 올바르지 않으므로 실제 하스켈이 아닙니다. –
참. 그러나 나는 수학 함수의 경우와 유사하게 "_을 쓰고 수학적 설명이므로 숫자 대신 함수에'^'를 사용하는 것이 좋습니다. 그럼에도 불구하고 연산자를 두 개를 구별하기 위해'.^'로 바꿀 것입니다. –
나는 수학에서'(.)^i'도보고 놀랐습니다. 아마도 그러한 유형의 공식 프레임 워크는 종속 유형 이론에 존재합니다. 그것은 흥미로울 것이다. –
이것은 맛의 문제이지만, 나는 그러한 스타일이 불쾌하다고 생각합니다. 먼저 의미가 무엇인지 설명하고 선호하는 대안을 제안합니다.
어떤 조작자에 대해서도 (f . g) x = f (g x)
과 (f ?) x = f ? x
을 알아야합니다. ?
. 이로부터 우리는
countWhere p = ((length .) . filter) p
= (length .) (filter p)
= length . filter p
그렇게
countWhere p xs = length (filter p xs)
내가 함수를 사용하는 것을 선호한다는 추론 그리고 countWhere = length .: filter
.:
(.:) :: (r -> z) -> (a -> b -> r) -> a -> b -> z
(f .: g) x y = f (g x y)
이라고 할 수 있습니다. 개인적으로 나는 이것이 훨씬 더 명확하다는 것을 안다.
(.:
너무 Data.Composition
아마 다른 장소에 정의되어 있습니다.)
'(. :) = fmap fmap fmap'으로'(. :)를 정의 할 수도 있습니다. 그것은 당신이 어떤 functor를 위해 사용할 수 있기 때문에 더 일반적입니다. 예를 들어'(* 2). : Just [1..5]'를 할 수 있습니다. 물론'(. :) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)'의 올바른 형태의 서명을 주어야합니다. –
@AaditMShah이 경우,'<$$> = fmap과 같은 것을 선호합니다. '(. :)'는'(->) r'을 전문으로하고''fmap''은'(->) r' 펑터에 있기 때문에'fmap'을 사용합니다. – kqr
(F입니다.).g는 원저자의 코드에 대한 훌륭한 위장 된 의견의 일부일 수도 있습니다. – Marton
그게 무슨 뜻인지 잘 모르겠습니다. –
이것은 저자가 영리 해지고 읽을 수없는 코드를 작성하는 것을 의미합니다. ;) – tibbe