답변:
$
연산자는 괄호를 회피하기위한 것이다. 그 후에 나타나는 것은 앞에 오는 것보다 우선합니다.
예를 들어 다음과 같은 줄이 있다고 가정 해 봅시다.
putStrLn (show (1 + 1))
이러한 괄호를 제거하려면 다음 행 중 하나도 동일한 작업을 수행합니다.
putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1
.
연산자 의 주요 목적은 괄호를 피하는 것이 아니라 함수를 연결하는 것입니다. 오른쪽에 나타나는 모든 출력을 왼쪽에 나타나는 모든 입력에 연결할 수 있습니다. 일반적으로 괄호가 적지 만 다르게 작동합니다.
같은 예로 돌아가서 :
putStrLn (show (1 + 1))
(1 + 1)
입력이 없으므로 .
연산자 와 함께 사용할 수 없습니다 .show
를 가져 와서 a Int
를 반환 할 수 있습니다 String
.putStrLn
를 가져 String
와서을 반환 할 수 있습니다 IO ()
.다음 과 같이 체인 show
을 연결할 수 있습니다 putStrLn
.
(putStrLn . show) (1 + 1)
원하는 괄호가 너무 많으면 $
연산자를 사용하여 제거하십시오 .
putStrLn . show $ 1 + 1
putStrLn . show . (+1) $ 1
것이 같습니다. 대부분의 (모두?) 접두사 연산자가 함수라는 것이 맞습니다.
map ($3)
. 내 말은, 주로 $
괄호를 피하기 위해 사용 하지만 그것이 전부는 아닙니다.
map ($3)
유형의 함수입니다 Num a => [(a->b)] -> [b]
. 숫자를 취하는 함수 목록을 가져 와서 3 개를 모두 적용하고 결과를 수집합니다.
유형과 정의가 다릅니다.
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x
($)
괄호를 피하기 위해 일반적인 함수 응용 프로그램을 대체하지만 다른 우선 순위를 갖습니다. (.)
새로운 기능을 만들기 위해 두 개의 기능을 함께 구성하기위한 것입니다.
어떤 경우에는 상호 교환이 가능하지만 일반적으로 사실이 아닙니다. 이들이있는 전형적인 예는 다음과 같습니다.
f $ g $ h $ x
==>
f . g . h $ x
다시 말해서 $
s 체인에서 , 마지막 체인을 제외한 모든 체인은.
x
함수 라면 어떨까요? 그런 다음 .
마지막으로 사용할 수 있습니까 ?
x
이이 맥락에서 실제로 적용한다면 , 그렇습니다. 그러나 "최종"은 다른 것보다 다른 것에 적용될 것 x
입니다. 을 적용하지 않으면 값 x
과 다르지 않습니다 x
.
또한주의 ($)
이다 기능 유형에 전문 신원 기능 . identity 함수는 다음과 같습니다.
id :: a -> a
id x = x
반면 ($)
다음과 같다 :
($) :: (a -> b) -> (a -> b)
($) = id
타입 시그니처에 의도적으로 여분의 괄호를 추가했습니다.
($)
연산자는 섹션에서 사용되지 않는 한 괄호를 추가하여 일반적으로 사용을 제거 할 수 있습니다. 예 : f $ g x
됩니다 f (g x)
.
의 사용은 (.)
대체하기가 약간 더 어렵다. 그들은 일반적으로 람다 또는 명시 적 함수 매개 변수의 도입이 필요합니다. 예를 들면 다음과 같습니다.
f = g . h
된다
f x = (g . h) x
된다
f x = g (h x)
도움이 되었기를 바랍니다!
($)
평가 순서를 제어하기 위해 괄호를 추가하지 않고 함수를 함께 연결할 수 있습니다.
Prelude> head (tail "asdf")
's'
Prelude> head $ tail "asdf"
's'
compose 연산자 (.)
는 인수를 지정하지 않고 새 함수를 작성합니다.
Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'
Prelude> let second = head . tail
Prelude> second "asdf"
's'
위의 예는 논쟁의 여지가 있지만 실제로는 컴포지션 사용의 편의성을 보여주지는 않습니다. 여기 또 다른 비유가 있습니다.
Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"
세 번째 만 한 번만 사용하면 람다를 사용하여 이름을 피할 수 있습니다.
Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"
마지막으로 구성은 람다를 피할 수 있습니다.
Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"
유용하고 매우 짧은 설명 에서 알아 내는 데 시간이 걸리는 하나의 응용 프로그램은 haskell을 배우십시오 .
f $ x = f x
그리고 infix 연산자를 포함하는 표현식의 오른쪽을 괄호로 묶으면 접두사 함수로 변환 ($ 3) (4+)
됩니다 (++", world") "hello"
.
왜 이런 짓을했을까요? 예를 들어 기능 목록. 양자 모두:
map (++", world") ["hello","goodbye"]`
과:
map ($ 3) [(4+),(3*)]
map (\x -> x ++ ", world") ...
또는 보다 짧습니다 map (\f -> f 3) ...
. 분명히 후자의 변형은 대부분의 사람들이 더 읽기 쉽습니다.
$3
공백없이 사용 하지 않는 것이 좋습니다. Template Haskell이 활성화 된 경우, 이것은 스플 라이스로 구문 분석되지만 $ 3
항상 말한 것을 의미합니다. 일반적으로 Haskell에서는 특정 연산자에 주위에 공백이 있다고 주장함으로써 구문의 일부를 "훔쳐"버리는 경향이있는 것으로 보입니다.
Haskell :
.
(점)과$
(달러 기호)의 차이점점
(.)
과 달러 기호 의 차이점은 무엇입니까($)
? 내가 이해하는 것처럼, 그들은 괄호를 사용할 필요가 없기 때문에 둘 다 구문 설탕입니다.
그것들은 괄호를 사용할 필요 가 없어서 구문 설탕이 아닙니다-그것들은 함수이며, 따라서 우리는 그들을 연산자라고 부를 수 있습니다.
(.)
및 사용시기.(.)
작성 기능입니다. 그래서
result = (f . g) x
인수로 전달 결과 전달 함수 구축과 동일 g
행 온 f
.
h = \x -> f (g x)
result = h x
(.)
작성하려는 함수에 전달할 인수가없는 경우에 사용하십시오 .
($)
및 사용시기($)
바인딩 우선 순위가 낮은 오른쪽 연관 적용 함수입니다. 따라서 단지 오른쪽에있는 것을 먼저 계산합니다. 그러므로,
result = f $ g x
절차 상으로 이것과 동일합니다 (Haskell이 게으르게 평가되기 때문에 중요합니다 f
.)
h = f
g_x = g x
result = h g_x
더 간결하게 :
result = f (g x)
($)
선행 함수를 결과에 적용하기 전에 평가할 모든 변수가있을 때 사용하십시오 .
우리는 각 기능의 소스를 읽음으로써 이것을 볼 수 있습니다.
소스 는 다음과 같습니다 (.)
.
-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
그리고 여기에 대한 소스 가 있습니다 ($)
:
-- | Application operator. This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- > f $ g $ h x = f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
기능을 즉시 평가할 필요가없는 경우 구성을 사용하십시오. 컴포지션에서 생성 된 함수를 다른 함수로 전달하려고 할 수 있습니다.
전체 평가를 위해 모든 인수를 제공 할 때 응용 프로그램을 사용하십시오.
예를 들어, 의미 적으로는
f $ g x
우리가 x
(또는 오히려 g
논쟁을 할 때 ), 그리고 할 때 :
f . g
우리가하지 않을 때.
... 또는 파이프 라이닝 을 사용하여 .
및 $
구성을 피할 수 있습니다 .
third xs = xs |> tail |> tail |> head
헬퍼 함수에 추가 한 후 :
(|>) x y = y x
$
운영자가 실제로 '더 F 번호 같은 작품이야 <|
그것보다 |>
일반적으로 하스켈에서이 같은 위의 함수를 써서 : third xs = head $ tail $ tail $ xs
또는 심지어 같은 third = head . tail . tail
F에 # 스타일의 구문이 같을 것이다 :let third = List.head << List.tail << List.tail
내 규칙은 간단합니다 (저도 초보자입니다).
.
매개 변수를 전달하려면 (함수 호출) 사용하지 마십시오.$
아직 매개 변수가 없으면 사용하지 마십시오 (함수 구성)그건
show $ head [1, 2]
그러나 결코 :
show . head [1, 2]
다른 모든 대답은 꽤 좋습니다. 그러나 ghc가 $를 처리하는 방법에 대한 중요한 유용성 세부 정보가 있습니다. ghc 유형 검사기는 더 높은 순위 / 수량화 된 유형으로 instatiarion을 허용합니다. $ id
예를 들어 유형을 살펴보면 인수 자체가 다형성 함수 인 함수를 사용하게됩니다. 그와 같은 작은 것들에는 동등한 화가 연산자와 동일한 유연성이 부여되지 않습니다. (이것은 실제로 $!가 같은 치료를받을 가치가 있는지 궁금해합니다)