2014-08-28 1 views
10

표현의 단순화에서 고통을 덜 수있는 방법이 있습니까? 나는 그것이 무엇을 의미하는지 설명 할 수있는 도구를보고 싶어요하스켈 배우기 - 표현을 단순화하는 방법?

(+) <$> a <*> b $ 1 

:이 표현 주어진 예를 들어

. instance Functor ((->) r)에 대한 Control.Monad.Instancesfmap를 참조 Data.Functor

(.) (+) a <*> b $ 1 

definition를 참조

fmap (+) a <*> b $ 1 

을 : 그것은 관련된 모든 단계와 표현을 단순화하기 위해 (연산자 우선 순위 검사, 소스의 올바른 인스턴스 함수 정의를 찾는) 초보자를위한 매우 힘든이다

등등.

EDIT : 명확히하기 위해, 나는 실제 함수 정의를 사용하여 표현식을 다시 작성하여 이식의 결과를 이해할 수있는 방법을 찾고있다. 여기에 (<$>) = fmap을 어떻게 말합니까? hoogle 및 다른 도구를 사용하여 특정 인스턴스 정의 (소스)를 찾는 방법을 모르겠습니다.

편집 : 다음 감소와 일치하는 잘못된 원본 표현식이 변경되었습니다.

답변

3

시작 ghci, 당신이 읽고있는 소스, :load 모듈 관심있는, 그리고 정보를 얻을 수있는 :i 명령을 사용의 기본 디렉토리에 :cd :

ghci> :i <$> 
(<$>) :: Functor f => (a -> b) -> f a -> f b 
    -- Defined in `Data.Functor' 
infixl 4 <$> 
ghci> :i $ 
($) :: (a -> b) -> a -> b -- Defined in `GHC.Base' 
infixr 0 $ 
ghci> :i . 
(.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base' 
infixr 9 . 

당신에게 알려줍니다 유형이 정의되어있는 곳에서 연관성 (infixl 또는 infixr)과 우선 순위 (숫자가 높을수록 더 가깝습니다). 따라서 (*10) <$> a $ 1((*10) <$> a) $ 1으로 읽습니다.

:load 모듈을 사용하면 해당 모듈 내부에있는 모든 이름의 범위가 ghci 범위 내에있게됩니다. 코드에서 오류가 발생하면 그 중 하나가 :i 안에 들어갈 수 없습니다. 이 경우에는 라인을 주석 처리하고 undefined을 사용하고 behlkir에서 제안한대로 입력 된 구멍을 사용할 수도 있습니다 (너무 많이 사용하지 않았 음).

ghci에서 :? 명령을 사용해보십시오.

6

나는 쉬운 방법이 GHCi 7.8에서 사용할 수 typed holes를 사용하는 것을 알게 :

> (*10) <$> _a $ 1 
Found hole ‘_a’ with type: s0 -> b 
Where: ‘s0’ is an ambiguous type variable 
     ‘b’ is a rigid type variable bound by 
      the inferred type of it :: b at <interactive>:4:1 
Relevant bindings include it :: b (bound at <interactive>:4:1) 
In the second argument of ‘(<$>)’, namely ‘_a’ 
In the expression: (* 10) <$> _a 
In the expression: (* 10) <$> _a $ 1 

그래서이 나에게 말한다 a :: s0 -> b있다. (

> :i (<$>) 
(<$>) :: Functor f => (a -> b) -> f a -> f b 
infixl 4 <$> 
> :i ($) 
($) :: (a -> b) -> a -> b 
infixr 0 $ 

그래서이 $가 높은 마우스 오른쪽 연관이라고 말한다 주어진 그것은, 그래서 a 함수해야 우리가 첫 번째 인수 될 함수해야한다하다고 볼 입력의 : 다음 사업자의 순서를 파악하는 것입니다 이중 확인). 즉, (*10) <$> a $ 1((*10) <$> a) $ 1과 동일하므로 먼저 (*10) <$> a에 초점을 맞 춥니 다.

> :t ((*10) <$>) 
((*10) <$>) :: (Num a, Functor f) => f a -> f a 
> :t (<$> _a) 
Found hole ‘_a’ with type: f a 
Where: ‘a’ is a rigid type variable bound by 
      the inferred type of it :: (a -> b) -> f b at Top level 
     ‘f’ is a rigid type variable bound by 
      the inferred type of it :: (a -> b) -> f b at Top level 
In the second argument of ‘(<$>)’, namely ‘_a’ 
In the expression: (<$> _a) 

그래서 우리는 functor가되도록 a이 필요합니다. 사용 가능한 인스턴스는 무엇입니까?

> :i Functor 
class Functor (f :: * -> *) where 
    fmap :: (a -> b) -> f a -> f b 
    (<$) :: a -> f b -> f a 
     -- Defined in ‘GHC.Base’ 
instance Functor Maybe -- Defined in ‘Data.Maybe’ 
instance Functor (Either a) -- Defined in ‘Data.Either’ 
instance Functor ZipList -- Defined in ‘Control.Applicative’ 
instance Monad m => Functor (WrappedMonad m) 
    -- Defined in ‘Control.Applicative’ 
instance Control.Arrow.Arrow a => Functor (WrappedArrow a b) 
    -- Defined in ‘Control.Applicative’ 
instance Functor (Const m) -- Defined in ‘Control.Applicative’ 
instance Functor [] -- Defined in ‘GHC.Base’ 
instance Functor IO -- Defined in ‘GHC.Base’ 
instance Functor ((->) r) -- Defined in ‘GHC.Base’ 
instance Functor ((,) a) -- Defined in ‘GHC.Base’ 

그래서 (->) r 우리가 a 함수이어야한다 알고 있기 때문에 굉장 하나 될 일이. Num 제약 조건에서 rNum a => a과 같아야합니다. 즉, (*10) <$> a :: Num a => a -> a을 의미합니다. 그런 다음 1을 적용하면 (*10) <$> a $ 1 :: Num a이됩니다. 여기서 a은 알 수없는 기능입니다.

이 모든 것은 GHCi를 사용하여 입력 된 구멍과 함께 :t:i을 사용하여 검색 할 수 있습니다. 물론, 상당한 수의 단계가 있지만, 복잡한 표현식을 분해하려고 할 때 결코 실패하지 않습니다. 다른 하위 표현식의 유형을 살펴보십시오.

5

GHCi는 훌륭하고 정확하게 제안되었으며, 나는 또한 제안했다.

나는 또한 빠른 검색이 활성화 된 상태 (오른쪽에서 상단 사이드 바에서 그것을위한 버튼이있다) 때문에, 당신은 훨씬을 제공 할 수있는, 매우 빠르게 기능 를 검색 할 수 있습니다, Hoogle을 제안 할

많은 GHCi보다 더 많은 정보를 얻을 수 있습니다. 가장 좋은 점은 모듈을 검색 할 필요가 없다는 것입니다. .

ghci> :t pure 
<interactive>:1:1: Not in scope: ‘pure’ 
ghci> :m +Control.Applicative 
ghci> :t pure 
pure :: Applicative f => a -> f a 

위의 Hoogle 링크가 하나에 불과합니다 (Haskell.org 사이트에서) : 먼저 가져와야 곳 GHCi 대조적이다. Hoogle은 컴퓨터 (cabal install hoogle)에 설치하고 명령 줄 (hoogle your-query)에서 쿼리를 실행할 수있는 프로그램입니다.
Sidenote : 먼저 정보를 수집하려면 hoogle data을 실행해야합니다. wget/curl이 필요하므로 Windows를 사용하는 경우 경로에서 처음으로 this을 얻어야합니다 (물론 Windows 용 말풍선). 리눅스에서는 거의 항상 내장되어 있습니다 (리눅스에 없으면 단지 apt-get입니다). 그런데 명령 행에서 Hoogle을 결코 사용하지는 않는다. 단지 접근하기 쉽지 않지만, 일부 텍스트 편집기와 플러그인이 그것을 활용할 수 있기 때문에 여전히 도움이 될 수있다.

FPComplete's Hoogle (내 경험상 제 3 자 라이브러리를 더 잘 알고 있기 때문에 더 만족할 수 있습니다. "Hoogling 세션"에서만 사용).

도중 Hayoo!도 있습니다. Hoogle에서

1 당신은 아마> 시간의 95 %는 몇 가지 이유가 (경우에 제 3의 라이브러리 때로는 인) 검색되고 있지 않은 경우 모듈을 가져 +Module을이 작업을 수행해야하지만하지 않습니다 .
-Module까지 모듈을 필터링 할 수도 있습니다. 예를 들어
: destroyTheWorld +World.Destroyer -World.Destroyer.MercydestroyTheWorld을 발견하고 당신이 그것을 할 수있는 자비 방법을보고하지 않을 있는지 확인하기 위해 (이것은, Data.Vector & Data.ByteString & Data.ByteString.Lazy에있는 것과 같은 다른 버전의 같은 함수 이름을 가진 모듈과 매우 편리 제공 Data.Vector.Mutable 등).

오, 그리고 Hoogle의 또 다른 장점은 함수의 서명을 보여줄뿐만 아니라 모듈의 Haddock 페이지로 이동하여 해당 페이지에서 문서를 얻을 수 있으며, 가능하면 클릭 할 수 있다는 것입니다. 모든 기능의 오른쪽에있는 "Source"에서 더 자세한 정보를 위해 구현 방법을 확인하십시오.

이 질문의 범위를 벗어나지 만, Hoogle은 함수 서명을 쿼리하는데도 사용됩니다. 색인 번호와 목록을 가져 와서 해당 색인의 요소를 제공하는 함수가 필요하다면 이미 내장되어 있는지 궁금하다. 몇 초 안에 검색 할 수있다.
나는이 함수가 숫자와리스트를 취하고 함수의 서명이이 라인을 따라 무엇인가 보일 수 있도록 목록의 요소를 제공한다는 것을 알고있다 : Int -> [a] -> a (또는 일반적으로 : Num a => a -> [b] -> b), 그리고 두 인스턴스 모두 실제로 나타난다. 이를위한 함수 ((!!)genericIndex).

GHCi는 표현을 가지고 놀 수 있고, 탐구 할 수있는 등 상상력이 풍부합니다. 추상적 인 기능을 많이 다루는 경우가 많습니다.
:l (oad)이 가능하다는 것은 매우 도움이됩니다.

기능 서명을 찾는 경우 Hoogle과 GHCi를 결합 할 수 있습니다.
GHCi에서 :! cmd을 입력 할 수 있으며 GHCi는 명령 줄에서 cmd을 실행하고 결과를 인쇄합니다. 즉 GHCi 내부에서도 Hoogle을 할 수 있습니다. :! hoogle void.

관련 문제