Совпадение шаблона Haskell по типу

Есть ли способ сделать что-то подобное в haskell?

data Fruits = Apple Int | Orange Int deriving (Eq, Show)

basket = [Apple 2, Orange 4]

from_basket t (x:basket) =
    case x of
        (t i) -> i
        _ -> from_basket t basket

Теперь я хочу получить "яблоко" из списка фруктов (корзины)

from_basket Apple basket

Без явного соответствия шаблону

case x of
    Apple i -> ...
    Orange i -> ...
    _ ->

Ответ 1

Одним из способов было бы определить вашу собственную вспомогательную функцию isApple, а затем выполнить фильтрацию:

isApple (Apple _) = True
isApple _         = False

getApples = filter isApple

Сравнение шаблонов - это инструмент по вашему выбору, я не знаю, можно ли это упростить. Но, кроме некоторого грязного шаблона Haskell, я не вижу другого способа.

Ответ 2

Другие ответы объяснили, почему он не будет работать так, как есть, но, поскольку альтернативы идут, желание сделать что-то подобное часто является признаком того, что ваши типы данных должны выглядеть примерно так:

data FruitName = Apple | Orange deriving (Eq, Show)
data Fruits = Fruits FruitName Int deriving (Eq, Show)

... в этом случае искомая функция становится тривиальной.

Ответ 3

Вы можете сделать что-то подобное этому, определяя функции селектора

getApple :: Fruits -> Maybe Int
getApple (Apple x) = Just x
getApple _ = Nothing

getOrange :: Fruits -> Maybe Int
getOrange (Orange x) = Just x
getOrange _ = Nothing

fromBasket selector [] = Nothing
fromBasket selector (x:basket) =
    case selector x of
        Just x -> Just x
        Nothing -> fromBasket selector basket

Теперь вы можете сделать

> fromBasket getApple basket
Just 2

> fromBasket getOrange basket
Just 4 

Это предполагает, что ваши конструкторы принимают аналогичные аргументы. Он также возвращает Nothing, если нужный тип плода не был в корзине.