Просто для пояснения, позвольте мне переписать ваш тип данных, чтобы избежать двусмысленности в значении 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
, которое определено выше. Странное сообщение об ошибке просто говорит вам, что функция не знает, как обращаться с членом типа SomeType, который не соответствует (I x)
.
Если вы определяете свой тип, используя более распространенный синтаксис:
data SomeType2 = X String | I Int | B Bool
тогда вы теряете эти прекрасные функции записи.
Сообщения об ошибках прекращают выполнение программы. Это иногда раздражает. Если вам нужно более безопасное поведение для ваших функций, ответ GBacon - это просто способ сделать это. Узнайте о типе Maybe a
и используйте его, чтобы справиться с такого рода вычислениями, которые должны возвращать некоторое значение или ничего не возвращать (попробуйте: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe).