Haskell 대수 데이터 유형의 대안 중에서 선택
-
13-09-2019 - |
문제
타입 X
다음과 같이 정의됩니다.
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
그리고 나는 원한다 Int
안에 X
값, 그렇지 않으면 0이있는 경우 값.
returnInt :: X -> Int
어떤 유형의 유형을 결정할 수 있습니까? X
논쟁 returnInt
이다?
해결책
여기서 점을 명확히하기 위해 x의 의미에서 모호성을 피하기 위해 데이터 유형을 다시 작성하겠습니다.
data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}
이 정의에는 x, i 및 b 유형이 없습니다. x, i 및 b입니다 유형 값을 만드는 생성자 Sometype
. GHCI에게 해당 유형 생성자로 구성된 값의 유형이 무엇인지 물어 보면 어떻게되는지 확인하십시오.
*Main> :t (I 5)
(I 5) :: Sometype
*Main> :t (B False)
(B False) :: Sometype
그들은 같은 유형에 속합니다 !!
X, I 및 B를 사용하여 유형을 구성 할 수있는 것처럼 패턴 매칭을 사용하여 위의 다른 답변에서 수행 한 것처럼 유형을 해체 할 수 있습니다.
returnInt :: SomeType -> Int
returnInt (I x) = x -- if the pattern matches (I x) then return x
returnInt _ = error "I need an integer value, you moron" -- throw an error otherwise
패턴 일치는 순서대로 발생한다는 것을 기억하십시오. 값이 일부 줄의 패턴과 일치하면 아래 줄의 패턴이 실행되지 않습니다.
당신이했던 것처럼 유형을 정의 할 때, 레코드 구문을 사용하는 것을 사용하십시오 (여기서보십시오. http://en.wikibooks.org/wiki/haskell/more_on_datatypes ), 당신은 무료로 그런 기능을 받았습니다 !!
예를 들어, MyInt의 유형을 살펴보십시오.
*Main> :t myInt
myInt :: SomeType -> Int
이 기능이 무엇을하는지보십시오.
*Main> myInt (I 5)
5
*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt
이것은 정확히 행동입니다 returnInt
위의 정의. 이상한 오류 메시지는 기능이 일치하지 않는 유형의 구성원을 처리하는 방법을 모른다는 것을 알려줍니다. (I x)
.
보다 일반적인 구문을 사용하여 유형을 정의하는 경우 :
data SomeType2 = X String | I Int | B Bool
그런 다음 멋진 레코드 기능을 풀어줍니다.
오류 메시지는 프로그램 실행을 종료합니다. 이것은 때때로 성가신 일입니다. 당신의 기능에 대해 더 안전한 행동이 필요하다면 Gbacon의 대답은 단지 그것을하는 방법입니다. 에 대해 알아보십시오 Maybe a
일부 가치를 반환하거나 아무것도 반환 해야하는 이런 종류의 계산에 대처하기 위해 유형을 사용하여 사용하십시오 (시도해보십시오. http://en.wikibooks.org/wiki/haskell/hierarchical_libraries/maybe ).
다른 팁
패턴 매칭을 사용하십시오.
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
가능한 모든 것에 대해보다 유연한 정의를 사용하십시오 X
값 :
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
그런 다음 사용할 수 있습니다 maybe
원하는 특정 불이행의 경우 0은 유효한 값일 수 있습니다 (이것은 반드시 문제):
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1
대조적으로, 부분 함수는 위험 런타임 예외 :
*Main> let returnInt (I i) = i
*Main> :t returnInt
returnInt :: X -> Int
*Main> returnInt (B True)
*** Exception: <interactive>:1:4-22: Non-exhaustive patterns in function returnInt
당신이 정말로 개구리를 느끼고 있다면, 당신은 사용할 수 있습니다 MonadPlus
returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero
더 많은 유연성을 얻으려면 :
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> returnInt (I 123) `mplus` returnInt (I 456) :: [Int]
[123,456]
다음과 같은 기능이 주어지면 :
returnInt :: X -> Int
returnInt x = {- some integer -}
... 유형 x
항상 X
. 당신이 신경 쓰는 것은 x
사용 X
, I
또는 B
생성자 유형.
패턴 매칭을 사용하여 차이점을 알려줍니다.
returnInt :: X -> Int
returnInt (X _) = error "needed an Int, got a String"
returnInt (I { iVal = n }) = n
returnInt (B _) = error "needed an Int, got a Bool"