2011-09-27 2 views

답변

13

예, 확장자는 ViewPatterns입니다. 목록이 비어 어디 아마 경우에 패턴을 추가 할 수 있습니다 있도록이 패턴은 항상 다른 last이 예외가 발생합니다,하지만 성공할 것

Prelude> :set -XViewPatterns 
Prelude> let f (last -> x) = x*2 
Prelude> f [1, 2, 3] 
6 

참고.

Prelude> f [] 
*** Exception: Prelude.last: empty list 

또한 구문 당도입니다. 당신은 여전히 ​​싱글 링크드리스트의 마지막 요소를 액세스하는 때문에 정상적인 패턴 매칭과는 달리,이, O (n)이입니다. 보다 효율적인 액세스가 필요한 경우 Data.Sequence과 같은 다른 데이터 구조를 사용하십시오. O (1) 양쪽에 액세스 할 수 있습니다.

+0

마지막으로 빈 목록에서 예외가 발생합니다. 내가 마지막으로, 머리, fst, snd에서 벗어나고 싶습니다. 빈 목록을 잘 처리하지 않는 함수. 예를 들어, 패턴 일치 (let x : xs) = "abcdefg"는 내가 내 질문에서 언급 한 것입니다. 안전하지 않은 prelude 함수를 사용하지 않고 마지막 요소를 얻는 비슷한 접근법이 있기를 바랬습니다. –

+2

@MichaelLitchard : 음, 예를 들어'Maybe '를 반환하는'safeLast' 함수를 정의 할 수 있습니다.이 함수는 패턴 일치를 적용하거나 목록을 역순으로 변환 한 다음 정상적인 패턴 일치를 사용할 수 있습니다. – hammar

+2

항상 성공하기 때문에 "패턴 일치"가 전혀 없습니다. 'f = (* 2). 마지막 '이 더 좋다. – u0b34a0f6ae

11

당신은리스트의 끝 부분에 패턴 매칭을 할 ViewPatterns을 사용하므로 항상 성공 때문에, 이제

{-# LANGUAGE ViewPatterns #-} 

을하고 viewFunction으로 reverse를 사용하도록 할 수 있습니다 예를 들어

printLast :: Show a => IO() 
printLast (reverse -> (x:_)) = print x 
printLast _ = putStrLn "Sorry, there wasn't a last element to print." 
그래서

모든 가능성을 다루는 한 예외를 throw하지 않는다는 점에서 이것은 안전합니다.

mainFunction (viewFunction -> pattern) = resultExpression

그렇게

mainFunction x = case viewFunction x of pattern -> resultExpression

에 대한 문법 설탕입니다

구문 (당신은. 예를 들어, Maybe을 반환를 재 작성 수) 당신은 그것을 단지 실제로 볼 수 있습니다 목록을 뒤집은 다음 그 패턴과 일치하지만 더 좋다고 느낍니다. viewFunction은 사용자가 좋아하는 기능입니다. (확장의 목적 중 하나는 그것에 기능을 정의 할 때 데이터 형식의 기본 구조를 사용하지 않은, 그래서 사람들이 깨끗하게 쉽게 패턴 매칭 기능 을 접근 사용할 수 있도록했다.)

4

다른 답변은 ViewPatterns 기반 솔루션을 설명합니다.

tailLast :: [a] -> Maybe ([a], a) 
tailLast [email protected](_:_) = Just (init xs, last xs) 
tailLast _ = Nothing 

pattern Split x1 xs xn = x1 : (tailLast -> Just (xs, xn)) 

를 다음 예와 같은 함수를 작성 : 당신은 그것을 일치와 같은 더 많은 패턴을 확인하려면, 당신은 PatternSynonym에 그 패키지 할 수 있습니다

foo :: [a] -> (a, [a], a) 
foo (Split head mid last) = (head, mid, last) 
foo _ = error "foo: empty list" 
2

이 하스켈 프로그램의 첫날이며, 또한 동일한 문제가 발생하지만 이전 솔루션에 제안 외부 유물의 어떤 종류를 사용하여 확인할 수 없습니다.

하스켈에 대한 제 느낌은 핵심 언어에 문제에 대한 해결책이 없다면 해결 방법은 언어에서 작동 할 때까지 문제를 변환하는 것입니다.

이 경우 문제를 변형하는 것은 꼬리 문제를 머리 문제로 변형시키는 것을 의미합니다. 이는 패턴 일치에서 유일하게 지원되는 작업으로 보입니다. 목록 반전을 사용하여 쉽게 수행 할 수 있으며 원래 목록에서 꼬리 요소를 사용하는 것처럼 머리 요소를 사용하여 역순 목록에서 작업하고 마지막으로 결과를 초기 순서로 되돌릴 수 있습니다 (예 : if 그것은 목록이었다).

예를 들어 정수 목록 (예 : [1,2,3,4,5,6])이 주어지면 끝에서 시작하여 원래 목록의 모든 두 번째 요소가있는이 목록을 작성한다고 가정합니다 그것의 두 배로 옮겨진다 (Homework1this excellent introduction to Haskell에서 가지고가는 운동) : [2,2,6,4,10,6]. 그것은 더 이상 이전의 솔루션보다 분명히입니다

revert :: [Integer] -> [Integer] 
revert []  = [] 
revert (x:[]) = [x] 
revert (x:xs) = (revert xs) ++ [x] 

doubleSecond :: [Integer] -> [Integer] 
doubleSecond []  = [] 
doubleSecond (x:[]) = [x] 
doubleSecond (x:y:xs) = (x:2*y : (doubleSecond xs)) 

doubleBeforeLast :: [Integer] -> [Integer] 
doubleBeforeLast l = (revert (doubleSecond (revert l))) 

main = putStrLn (show (doubleBeforeLast [1,2,3,4,5,6,7,8,9])) 

, 그러나 그것은 나에게 더 하스켈 틱 느낌 :

그런 다음 우리는 다음을 사용할 수 있습니다.

+1

StackOverflow에 오신 것을 환영합니다. 축하해주세요! 상대방을 액세스하기 위해 목록을 반대로 바꾸는 것은 정말로 매우 하스 켈리시 (Haskellish) 솔루션입니다. (오히려 비효율적이긴하지만, 'last'를 사용하면 여러 번 해봐야 할 때 더욱 악화 될 수 있습니다 ... 성능이 중요하고 액세스해야하는 경우 마지막 요소이면 목록이 적절한 유형이 아님). – leftaroundabout

+0

감사합니다. 나의 신참 선수 수준에서, 나는 성능에 미치는 영향을 관찰하기보다 하스켈 프로그래밍 관용구를 발견하는 데 더 많은 관심이 있습니다. 간단히 말해서 역순으로 연결된리스트를 사용하는 것이 더 나쁜 경우이며, 실제로 하스켈이 테일 패턴 매칭을 제공하지 않는 이유라고 생각합니다. (하스켈 목록은 단순히 단순 연결 목록을 사용하여 구현됩니다.) – OlivierD

+1

맞음. 하스켈리스트는 스택이나 무한한 스트림처럼 훌륭하지만 무작위 액세스에는 정말 좋지 않으며 상대편에 액세스하는 것은 중간에있는 요소에 액세스하는 것보다 낫습니다. – leftaroundabout

관련 문제