Ngoài câu trả lời của @ DanielWagner, cách khác là sử dụng Scrap your boilerplate (AKA "SYB"). Nó cho phép bạn tìm thấy subterm đầu tiên của một loại nhất định. Vì vậy, bạn có thể xác định
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Monad
import Data.Data
import Data.Generics.Schemes
import Data.Typeable
data Foo = X (String, Int) | A String | B String | C String | D String
deriving (Show, Eq, Ord, Data, Typeable)
fooString :: Foo -> Maybe String
fooString = msum . gmapQ cast
và fooString
sẽ trả lại đối số đầu tiên String
của các nhà thầu của bạn. Chức năng cast
lọc ra String
s và gmapQ
nhận các giá trị được lọc cho tất cả các lớp con ngay lập tức.
Tuy nhiên, điều này sẽ không trả lại String
từ X
, vì X
không có ngay lập tức String
subterm, nó chỉ có một subterm loại (String, Int)
. Để có được String
đầu tiên bất cứ nơi nào trong hệ thống phân cấp hạn, bạn có thể sử dụng everywhere
:
fooString' :: Foo -> Maybe String
fooString' = everything mplus cast
Lưu ý rằng phương pháp này là hơi mong manh: Nó bao gồm đơn giản là tất cả String
là nó tìm thấy, trong đó có thể không phải luôn luôn những gì bạn muốn , đặc biệt, nếu sau này bạn mở rộng kiểu dữ liệu của mình (hoặc một số kiểu dữ liệu mà nó tham chiếu).
Nguồn
2015-08-22 18:39:22
Khi không có ngôn ngữ nào có sẵn trong ngôn ngữ (ngoại trừ, bạn có thể cân nhắc sử dụng [generics] (https://wiki.haskell.org/Generics) hoặc [Template Haskell] (https: //wiki.haskell. org/Template_Haskell) để tạo mã như vậy, nó có hợp lý cho trường hợp sử dụng của bạn không? –