문제

은 무엇이 덜 알려진 그러나 유용한 기능의 메인 프로그램이 들어 있습니다.(나는 언어를 이해하고 그 자체이 덜 알려진,그러나 나와 함께 일.도 설명의 간단한 일이에서 구현,다음과 같이 정의 피보나치 한 줄의 코드를 얻을 것이다,회가 직접 참여 할 수있는 기회입니다.)

  • 를 제한하려고 답켈 core
  • 하나의 기능당 응답
  • 예를 들어 설명의 기능이 아니라 단지에 대한 링크를 설명서
  • 레이블을 사용하여 이 기능을 사용하 굵은 제목으로 첫 번째 줄
도움이 되었습니까?

해결책

내 뇌는 방금 폭발했다

이 코드를 컴파일하려는 경우 :

{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Foo a
ignorefoo f = 1 where Foo a = f

이 오류 메시지가 표시됩니다.

$ ghc Foo.hs

Foo.hs:3:22:
    My brain just exploded.
    I can't handle pattern bindings for existentially-quantified constructors.
    Instead, use a case-expression, or do-notation, to unpack the constructor.
    In the binding group for
        Foo a
    In a pattern binding: Foo a = f
    In the definition of `ignorefoo':
        ignorefoo f = 1
                    where
                        Foo a = f

다른 팁

사용자 정의 제어 구조

Haskell에는 속기 3 개 운영자가 없습니다. 내장 if-then-else 항상 3 대이며 표현입니다 (필수 언어는 가지고있는 경향이 있습니다. ?:= 표현, if= 진술). 그래도 원한다면

True ? x = const x
False ? _ = id

정의합니다 (?) 3 대 연산자가 되려면 :

(a ? b $ c)  ==  (if a then b else c)

자신의 단락 논리 연산자를 정의하기 위해 대부분의 다른 언어로 매크로에 의지해야하지만 Haskell은 완전히 게으른 언어이므로 작동합니다.

-- prints "I'm alive! :)"
main = True ? putStrLn "I'm alive! :)" $ error "I'm dead :("

hoogle

Hoogle은 당신의 친구입니다. 나는 "핵심"의 일부가 아니라고 인정합니다. cabal install hoogle

이제 "고차 기능을 찾고 있다면 이미 거기에 있습니다"(임시의 의견). 그러나 그 기능을 어떻게 찾습니까? Hoogle과 함께!

$ hoogle "Num a => [a] -> a"
Prelude product :: Num a => [a] -> a
Prelude sum :: Num a => [a] -> a

$ hoogle "[Maybe a] -> [a]"
Data.Maybe catMaybes :: [Maybe a] -> [a]

$ hoogle "Monad m => [m a] -> m [a]"
Prelude sequence :: Monad m => [m a] -> m [a]

$ hoogle "[a] -> [b] -> (a -> b -> c) -> [c]"
Prelude zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

Hoogle-Google 프로그래머는 컴퓨터의 도움으로 자신이하는 방식과 같은 방식으로 자신의 프로그램을 종이에 쓸 수 없습니다. 그러나 그와 기계는 함께 인정받지 못하는 강제입니다.

BTW, Hoogle을 좋아한다면 Hlint를 확인하십시오!

자유 정리

Phil Wadler는 우리에게 a의 개념을 소개했습니다 자유 정리 그리고 우리는 그 이후로 Haskell에서 그들을 학대 해 왔습니다.

Hindley-Milner 스타일 유형 시스템 의이 멋진 유물은 매개 변수를 사용하여 기능에 대해 이야기함으로써 정식 추론을 돕습니다. ~하지 않을 것이다 하다.

예를 들어, 모든 Functor 사례를 충족 해야하는 두 가지 법이 있습니다.

  1. forall f g. fmap f. fmap g = fmap (f. g)
  2. FMAP ID = ID

그러나 자유 정리는 우리가 첫 번째 것을 증명하는 것을 귀찮게 할 필요는 없지만, 두 번째는 유형 시그니처에서 '무료'로 온다!

fmap :: Functor f => (a -> b) -> f a -> f b

게으름에 약간 조심해야하지만 이것은 원래 논문과 Janis Voigtlaender 's에서 부분적으로 덮여 있습니다. 더 최근의 논문 자유 정리가있을 때 seq.

공통 목록 작업의 속기

다음은 동일합니다.

concat $ map f list
concatMap f list
list >>= f

편집하다

자세한 내용이 요청되었으므로 ...

concat :: [[a]] -> [a]

concat 목록 목록을 가져 와서 단일 목록으로 연결합니다.

map :: (a -> b) -> [a] -> [b]

map 목록 위에 함수를 맵핑합니다.

concatMap :: (a -> [b]) -> [a] -> [b]

concatMap 동일합니다 (.) concat . map: 목록에 함수를 매핑하고 결과를 연결하십시오.

class Monad m where
    (>>=) :: m a -> (a -> m b) -> m b
    return :: a -> m a

Monad a 묶다 호출되는 작동 >>= Haskell (또는 설탕 do-동등한). 목록, 일명 [],, a Monad. 우리가 대체한다면 [] ~을 위한 m 위에서 :

instance Monad [] where
    (>>=) :: [a] -> (a -> [b]) -> [b]
    return :: a -> [a]

자연스러운 것은 무엇입니까 Monad 목록에서 수행 할 작업? 우리는 모나드 법을 만족시켜야합니다.

return a >>= f           ==  f a
ma >>= (\a -> return a)  ==  ma
(ma >>= f) >>= g         ==  ma >>= (\a -> f a >>= g)

구현을 사용하는 경우 이러한 법률이 보유하고 있는지 확인할 수 있습니다.

instance Monad [] where
    (>>=) = concatMap
    return = (:[])

return a >>= f  ==  [a] >>= f  ==  concatMap f [a]  ==  f a
ma >>= (\a -> return a)  ==  concatMap (\a -> [a]) ma  ==  ma
(ma >>= f) >>= g  ==  concatMap g (concatMap f ma)  ==  concatMap (concatMap g . f) ma  ==  ma >>= (\a -> f a >>= g)

이것은 실제로 행동입니다 Monad []. 데모로서

double x = [x,x]
main = do
    print $ map double [1,2,3]
        -- [[1,1],[2,2],[3,3]]
    print . concat $ map double [1,2,3]
        -- [1,1,2,2,3,3]
    print $ concatMap double [1,2,3]
        -- [1,1,2,2,3,3]
    print $ [1,2,3] >>= double
        -- [1,1,2,2,3,3]

중첩 가능한 멀티 린 댓글.

{- inside a comment,
     {- inside another comment, -}
still commented! -}

일반화 된 대수 데이터 유형. 다음은 유형 시스템이 모든 사례를 다룰 수있는 예제 통역사입니다.

{-# LANGUAGE GADTs #-}
module Exp
where

data Exp a where
  Num  :: (Num a) => a -> Exp a
  Bool :: Bool -> Exp Bool
  Plus :: (Num a) => Exp a -> Exp a -> Exp a
  If   :: Exp Bool -> Exp a -> Exp a -> Exp a 
  Lt   :: (Num a, Ord a) => Exp a -> Exp a -> Exp Bool
  Lam  :: (a -> Exp b) -> Exp (a -> b)   -- higher order abstract syntax
  App  :: Exp (a -> b) -> Exp a -> Exp b
 -- deriving (Show) -- failse

eval :: Exp a -> a
eval (Num n)      = n
eval (Bool b)     = b
eval (Plus e1 e2) = eval e1 + eval e2
eval (If p t f)   = eval $ if eval p then t else f
eval (Lt e1 e2)   = eval e1 < eval e2
eval (Lam body)   = \x -> eval $ body x
eval (App f a)    = eval f $ eval a

instance Eq a => Eq (Exp a) where
  e1 == e2 = eval e1 == eval e2

instance Show (Exp a) where
  show e = "<exp>" -- very weak show instance

instance (Num a) => Num (Exp a) where
  fromInteger = Num
  (+) = Plus

최상위 바인딩의 패턴

five :: Int
Just five = Just 5

a, b, c :: Char
[a,b,c] = "abc"

얼마나 멋진가요! 그 전화를 저장합니다 fromJust 그리고 head 때때로.

선택적 레이아웃

공백 (일명 레이아웃) 대신 명시 적 버팀대와 세미콜론을 사용하여 블록을 구분할 수 있습니다.

let {
      x = 40;
      y = 2
     } in
 x + y

... 또는 동등하게 ...

let { x = 40; y = 2 } in x + y

... 대신에 ...

let x = 40
    y = 2
 in x + y

레이아웃이 필요하지 않기 때문에 다른 프로그램에서 Haskell 프로그램을 간단하게 제작할 수 있습니다.

seq 그리고 ($!) 만 평가합니다 무언가가 바닥이 아닌지 확인하기에 충분합니다.

다음 프로그램은 "거기"만 인쇄합니다.

main = print "hi " `seq` print "there"

Haskell에 익숙하지 않은 사람들의 경우 Haskell은 일반적으로 강력하지 않으므로 함수에 대한 인수는 필요한 경우에만 평가됩니다.

예를 들어, 다음은 "무시"하고 성공으로 종료됩니다.

main = foo (error "explode!")
  where foo _ = print "ignored"

seq 첫 번째 인수가 맨 아래에있는 경우 바닥으로 평가하여 해당 동작을 변경하는 것으로 알려져 있습니다.

예를 들어:

main = error "first" `seq` print "impossible to print"

... 또는 동등하게, 이슈가 없어 ...

main = seq (error "first") (print "impossible to print")

... "첫 번째"에 오류가 발생합니다. "인쇄 불가능"은 결코 인쇄되지 않습니다.

그래서 그럼에도 불구하고 seq 엄격합니다. 열성적인 언어가 평가하는 방식으로 평가하지 않습니다. 특히, 다음 프로그램에서 모든 긍정적 인 정수를 강요하려고 시도하지는 않습니다. 대신, 그것은 그것을 확인합니다 [1..] 바닥이 아닙니다 (즉시 찾을 수 있음), "완료"및 종료.

main = [1..] `seq` print "done"

연산자 고정

당신은 사용할 수 있습니다 Infix, Infixl 또는 Infixr 운영자 연관성과 우선 순위를 정의하는 키워드. 예제 참조:

main = print (1 +++ 2 *** 3)

infixr  6 +++
infixr  7 ***,///

(+++) :: Int -> Int -> Int
a +++ b = a + 2*b

(***) :: Int -> Int -> Int
a *** b = a - 4*b

(///) :: Int -> Int -> Int
a /// b = 2*a - 3*b
Output: -19

디픽스 후 숫자 (0 ~ 9)를 사용하면 연산자의 우선 순위를 정의 할 수 있습니다. Infixl은 왼쪽과 Infixr가 오른쪽으로 연관성을 의미하는 반면, Infix는 연관성이 없다는 것을 의미합니다.

이를 통해 복잡한 연산자를 정의하여 간단한 표현식으로 작성된 높은 수준의 작업을 수행 할 수 있습니다.

백 티크 사이에 이진 함수를 연산자로 사용할 수도 있습니다.

main = print (a `foo` b)

foo :: Int -> Int -> Int
foo a b = a + b

따라서, 당신은 그들에 대한 우선 순위를 정의 할 수도 있습니다.

infixr 4 `foo`

괄호를 피합니다

그만큼 (.) 그리고 ($) 기능 Prelude 많은 곳에서 괄호를 피할 수 있도록 매우 편리한 고정성이 있습니다. 다음은 동일합니다.

f (g (h x))
f $ g $ h x
f . g $ h x
f . g . h $ x

flip 도움도 다음과 동일합니다.

map (\a -> {- some long expression -}) list
flip map list $ \a ->
    {- some long expression -}

예쁜 경비원

Prelude 정의합니다 otherwise = True, 완전한 가드 조건을 자연스럽게 읽게합니다.

fac n
  | n < 1     = 1
  | otherwise = n * fac (n-1)

C 스타일 열거

최상위 패턴 매칭과 산술 시퀀스를 결합하면 연속 값을 정의하는 편리한 방법을 제공합니다.

foo : bar : baz : _ = [100 ..]    -- foo = 100, bar = 101, baz = 102

읽을 수있는 기능 구성

Prelude 정의합니다 (.) 수학적 기능 구성이되기; 그건, g . f 먼저 적용됩니다 f, 그런 다음 적용됩니다 g 결과에.

만약 너라면 import Control.Arrow, 다음은 동일합니다.

g . f
f >>> g

Control.Arrow 제공합니다 instance Arrow (->), 그리고 이것은 기능 응용 프로그램을 거꾸로 읽고 싶지 않은 사람들에게 좋습니다.

let 5 = 6 in ... 유효한 haskell입니다.

무한한 목록

Fibonacci를 언급 한 이후로 매우 우아한 방법이 있습니다. 피보나치 번호 생성 이와 같은 무한한 목록에서 :

fib@(1:tfib)    = 1 : 1 : [ a+b | (a,b) <- zip fib tfib ]

@ 연산자를 사용하면 1 : TFIB 구조에서 패턴 일치를 사용할 수 있으며 전체 패턴을 FIB라고합니다.

이해 목록은 무한 재귀로 들어가서 무한 목록을 생성합니다. 그러나 유한 금액을 요청하는 한 다음과 같은 요소를 요청하거나 작동 할 수 있습니다.

take 10 fib

요청하기 전에 모든 요소에 작업을 적용 할 수도 있습니다.

take 10 (map (\x -> x+1) fib)

이것은 Haskell의 매개 변수 및 목록에 대한 게으른 평가 덕분입니다.

모듈 수입 및 수출의 유연한 사양

수입 및 내보내기가 좋습니다.

module Foo (module Bar, blah)  -- this is module Foo, export everything that Bar expored, plus blah

import qualified Some.Long.Name as Short
import Some.Long.Name (name)  -- can import multiple times, with different options

import Baz hiding (blah)  -- import everything from Baz, except something named 'blah'

목록이나 고차 기능을 찾고 있다면 이미 있습니다.

표준 라이브러리에는 많은 편의성과 고차 기능이 있습니다.

-- factorial can be written, using the strict HOF foldl':
fac n = Data.List.foldl' (*) 1 [1..n]
-- there's a shortcut for that:
fac n = product [1..n]
-- and it can even be written pointfree:
fac = product . enumFromTo 1

정식 추론

Haskell은 순전히 기능적이기 때문에 겹치지 않는 패턴이없는 경우 동일한 부호를 실제 동등한 부호로 읽을 수 있습니다.

이를 통해 정의를 코드로 직접 대체 할 수 있으며 최적화 측면에서 작업이 발생할 때 컴파일러에게 많은 여유를 제공합니다.

이러한 형태의 추론의 좋은 예는 여기에서 찾을 수 있습니다.

http://www.haskell.org/pipermail/haskell-cafe/2009-march/058603.html

이것은 또한 사례의 유효한 구성원 (예 : Monad 법)에 대해 예상되는 법률 또는 규칙의 형태로 잘 나타납니다.

  1. Returrn a >> = f == fa
  2. m >> = return == m
  3. (m >> = f) >> = g == m >> = ( x-> fx >> = g)

종종 모나디 코드를 단순화하는 데 사용할 수 있습니다.

게으름

유비쿼터스 게으름을 의미하는 것과 같은 활동을 할 수 있습을 정의

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

하지만 그것 또한 제공합니다으로 우리를 많이 더 미묘한 혜택의 측면에서 구문 및 추론이다.

예를 들어,으로 인해 엄격 ML 을 처리 값이 제한, 하고,매우 주의깊게 추적형시키 바인딩하지만,Haskell,우리가 할 수 있게 모든 하자는 반복될 필요가 없을 구분 valfun.이것을 제거하는 중요한 구문 사마귀에서 언어입니다.

이는 간접적으로 제공 상승을 우리의 사랑스러운 where 절,우리가 할 수 있기 때문에 안전하게 이동하는 계산을 수 있습니다 또는 사용할 수 없습의 주요 흐름 제어 및 보의 게으름과 거래를 공유하는 결과입니다.

우리는 우리를 대체할 수 있는(거의)모든 ML 스타일의 기능이 필요하()반환 값으로 그냥 지연 계산의 값으로 설정합니다.유가 있는 이렇게 하는 것을 피하기 위하여 시간에서 유출 방지 할 공간 CAFs, 지만,이러한 경우는 드물다.

마지막으로,그것은 허용 무제한 eta 감소(\x -> f x 대체될 수 있으로 f).이것은 연결자 지향 프로그래밍을 위해 같은 것들을 파서 연결자들보다 훨씬 더 쾌적한 작업으로 비슷한 구문에 엄격한 언어입니다.

이것은 당신이 때론 프로그램에 대한 지점에서 무료 스타일에 또는에 대해 다시 쓰기로 포인트-무료 스타일을 줄여 인수 소음.

병렬 목록 이해력

(특별한 GHC- 기능)

  fibs = 0 : 1 : [ a + b | a <- fibs | b <- tail fibs ]

향상된 패턴 매칭

  • 게으른 패턴
  • 반박 할 수없는 패턴

    let ~(Just x) = someExpression
    

보다 패턴 매칭

열거

인스턴스 인 모든 유형 열거적 숫자뿐만 아니라 산술 순서에서 사용할 수 있습니다.

alphabet :: String
alphabet = ['A' .. 'Z']

자신의 데이터 유형을 포함하여 기본 구현을 얻으려면 Enum에서 파생됩니다.

data MyEnum = A | B | C deriving(Eq, Show, Enum)

main = do
    print $ [A ..]                 -- prints "[A,B,C]"
    print $ map fromEnum [A ..]    -- prints "[0,1,2]"

모나드

그들은 그다지 숨겨져 있지 않지만, 당신이 생각하지 않는 곳 (목록, 아마도 유형) ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top