2015-07-03 15 views
6

Ben tür imzası data NamedPoint = NamedPoint String Int IntBir veri yapısını alan ve içindeki tüm satırları döndüren genel bir işlev var mı?

data Person = Name Int Int Int 

gibi görünecektir ve REPL kullanmadan şu şekilde görünecektir f :: a -> [Int] veri girişi gibi görünecektir düşünüyorum:

>> let namedPoint = NamedPoint "hey" 1 2 
>> let tommy = Person "Tommy" 1 2 3 
>> f namedPoint 
>> [1,2] 
>> f Tommy 
>> [1,2,3] 

Bunun gibi yararlı olacağını düşünüyorum Parametreler bir sürü veri için alıcılar yazmak için çok tembel olduğunuz zaman kayıtları için bir alternatif.

+3

'' neden işlev 'f :: NamedPoint -> [Int]' 'olarak yazılmıyor? – zegkljan

+0

Bu durumda olabilir. Ama bu davranışın genelleştirilmiş türleri ayıklamak için yararlı olabileceğini düşünüyordum. soruyu daha spesifik olmak için düzenledim. – user514156

+0

Bu görev için, uniplate en basit seçimdir. F'iniz sadece evrenBi işlevidir. – augustss

cevap

10

Data sınıfı bununla ilgilenir. Onunla çalışmak için en kolay yolu, lens paketinden template traversal ile buldum. Bu temel olarak, Data örneğiyle bir şey ayarlamanıza veya almanıza izin verir. GHCi; a geçişi olan

> import Data.Data 
> import Control.Lens 
> import Data.Data.Lens 

> -- Data is a derivable class 
> :set -XDeriveDataTypeable 
> data NamedPoint = NamedPoint String Int Int deriving (Data, Show) 
> data Person = Name String Int Int Int deriving (Data, Show) 
> let namedPoint = NamedPoint "hey" 1 2 
> let tommy = Name "Tommy" 1 2 3 

> let ints = toListOf template :: Data a => a -> [Int] 
> ints namedPoint 
[1,2] 
> ints tommy 
[1,2,3] 

template olduğundan, ayrıca değerleri üzerinden map (ancak bunları türünü belirtmek gerekebilir): girdi verileri `` NamedPoint olacak olursa

> namedPoint & template *~ (10 :: Int) 
NamedPoint "hey" 10 20 
> import Data.Char 
> tommy & template %~ toUpper 
Name "TOMMY" 1 2 3 
9

Bu, anlattığınız tür imzasının bir işleviyle mümkün değildir. f :: a -> [Int]'un ne anlama geldiğini düşünün: f, herhangi bir olası tip değerini alan ve Int s listesini döndüren bir işlev olmalıdır. Böyle bir işlev nasıl tanımlanmalıdır? Eğer senin a, neden sadece bu türü kullanmak olacak biliyorsanız yalnızca olası tanım o

f :: a -> [Int] 
f _ = [0] 

gibi bir şey argüman yok sayar ve sabit bir değer döndürdüğünü mı? Şunun gibi:

f :: NamedPoint -> [Int] 
f (NamedPoint _ a b) = [a, b] 

bir veri türü tüm Int s dönen bazı "genel" fonksiyonunu isteseydim, tek seçenek olan veri türleri için örneklerini bir typeclass

class IntContainer a where 
    f :: a -> [Int] 

tanımlamak ve sonra tanımlamak olacaktır

instance IntContainer NamedPoint where 
    f (NamedPoint _ a b) = [a, b] 
+0

Bu kullanım durumum için çalışacağım düşünüyorum teşekkürler! – user514156

+1

"Bu mümkün değil" biraz abartı - önemsiz değil, tam olarak belirtilen tam imzayla mümkün değildir ('a :: [Int]') fakat OP'nin ne istediğini elde etmek kesinlikle mümkündür. –

+0

@ErikAllik Bildirdiğiniz için teşekkür ederim. Cevabı daha doğru olarak düzenledim. – zegkljan