2016-06-04 7 views
5

Java'daki sınıfları Haskell'in functor'larına benzer şekilde tanımlamaya çalışıyorum. olarak vesile, bir funktor tanımlanır: Bir Identity Functor over types functor uygulamak istiyorsanızJava'daki İşlevler

/** 
* Programming languages allow only (just simply enough) endofunctor, that are functors from and to the same category. 
* In this case, the category is the one of the datatypes (in here Type, in order to make it more clear) 
*/ 
public interface EndoFunctor<X extends Type> extends Type { 

    /** 
    * The basic implementation for any element fx 
    * @param map Transformation function for the type parameter 
    * @param fx Element of the current class 
    * @param <Y> Target type 
    * @return  transformed element through map 
    */ 
    <Y extends Type> EndoFunctor<Y> fmap(Function<X,Y> map, EndoFunctor<X> fx); 

} 

, ben bu kod ile

public class Id<X extends Type> implements EndoFunctor<X> { 
    protected X witness; 
    Id(X witness) { this.witness = witness; } 
    @Override 
    public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) { 
     return new Id<>(map.apply(fx.witness)); 
    } 
} 

sorun gibi bir şey yazmak zorunda Id<X> türüyle uyumlu olmamasıdır EndoFunctor<X>. Nasıl, (Benim nesne bir Id<T> olduğunu biliyoruz çünkü yani, her tür K<T>EndoFunctor<T> uygulayan ve bir harita işlevi T->U verilirse, o zaman K<U> herhangi tiplemeleri olmadan, bir değer olarak döndürülür EndoFunctor arayüzü böyle de fmap belirleyebilir daha sonra fmap sonucu "Id<U> olması gerekir, ve bu yüzden tür tipi EndoFunctor<U> sonucunu downcast down)?

+0

Bunun yerine, 'EndoFunctor fmap (İşlev map) 'kullanmamış olmanızın bir nedeni var mı? Bu şekilde, her örnek kendi örnek değişkenlerini kullanır. I.e., 'new Id döndürme <> (map.apply (this.witness))'. – afsantos

+0

Bu gözlemin soruma cevap verebileceğini sanmıyorum. Haritanız ('fmap2 (x)') 'fmap (x, this)' olarak tanımlanabilir, bu yüzden bu tip problemi gerçekten çözmez. – jackb

+0

Bu arada, işlevi bir funker'in tanımına daha çok benzetmek için bu şekilde tanımladım, yani [F: (a-> b) -> (Fa -> Fb)] (http: // Bu durumda F, EndoFunctor olan latex.codecogs.com/gif.download?F%5Ccolon%20%28a%5Cto%20b%29%5Cto%20%28Fa%5Cto%20Fb%29). – jackb

cevap

7

Sen CRTP kullanabilirsiniz:

interface EndoFunctor<X extends Type, T extends EndoFunctor<X, T>> extends Type { 
    <Y extends Type> EndoFunctor<Y, ?> fmap(Function<X,Y> map, T fx);  
} 

class Id<X extends Type> implements EndoFunctor<X, Id<X>> { 
    protected X witness; 
    Id(X witness) { this.witness = witness; } 

    @Override 
    public <Y extends Type> Id<Y> fmap(Function<X, Y> map, Id<X> fx) { 
     return new Id<>(map.apply(fx.witness)); 
    } 
} 
+0

Bu yaklaşım, daha sonra kodumda sahip olduğum diğer sorunları (sizi sıkmayacağım) çözüyor. Teşekkürler – jackb

2

sorun EndoFunctor<X> uymadığını Id<X> değil, ama sen fmap geçersiz kılmak için çalıştık zaman parametre tipleri daha spesifik yapmış ve sonuç yöntem imzası artık bu o Id<X> tam EndoFunctor<X> arabirimini uygulamıyor bugünkü halini demektir EndoFunctor

içinde fmap yöntemi imzası ile eşleşir. Bir arayüz uygularken, bunun farklı bir arayüz olduğunu bilmeden sınıfınızla etkileşime girmesi mümkün olmalıdır.

Arabirim ile uyumlu olmasını sağlamak için bu yöntem parametresini kaldırmaya ve örnek değişkeni kullanarak ya da Id<X> ile public <Y extends Type> Id<Y> fmap(Function<X, Y> map, EndoFunctor<X> fx) arasındaki imzayı değiştirmeyle ilgili açıklamalarda yer alan tavsiyeleri uygulayın.

+0

Tavsiyeniz yukarıda açıklandığı gibi benzer bir soruna sahiptir: bunu yaparak, yalnızca belirli bir geri dönüş türüne izin veriyorum. – jackb

8

ben EndoFunctor arayüzünde fmap belirleyebilir nasıl öyle ki her türlü K EndoFunctor ve bir harita işlevi uygulaması halinde T-> U (yani bu yana, herhangi bir tiplemeleri olmadan, daha sonra K, bir değer olarak döndürülür verilir Nesnemin bir Kimlik olduğunu biliyorum, o zaman fmap'in sonucu "bir" olmak zorundadır ve bu yüzden EndoFunctor türünü bu tür bir türe indirgeyim)?

Yapamazsınız; Buna daha iyi nazik polimorfizm denir ve Java bunu desteklemez (çok az dil). Jorn Vernee cevabı size Java can yakın alır, ama o arayüzü

class NotId<X extends Type> implements EndoFunctor<X, Id<X>> { 

    @Override 
    public <Y extends Type> ADifferentEndoFunctorAgain<Y> fmap(Function<X, Y> map, Id<X> fx) { ... } 
} 

yazmasına olanak tanır ve bir belirli ile EndoFunctor s üzerinde jenerik çalışmak yerine kod yazmak istiyorsanız işe yaramaz EndoFunctor, Id gibi.

+0

Aslında, bazı kaldırma işlemlerini gerçekleştirmenin bu konuda yardımcı olacağını umuyordum. Cevabınız resmen doğruydu, bir öncekse kod yazmama yardım etti. Çok kötü, aynı anda iki cevabı kabul edemem. – jackb