String'i neden tip sınıfının bir örneği yapamıyorum?


85

Verilen :

data Foo =
  FooString String
class Fooable a where --(is this a good way to name this?)
  toFoo :: a -> Foo

Şunun Stringbir örneğini yapmak istiyorum Fooable:

instance Fooable String where
  toFoo = FooString

GHC daha sonra şikayet ediyor:

Illegal instance declaration for `Fooable String'
    (All instance types must be of the form (T t1 ... tn)
     where T is not a synonym.
     Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Fooable String'

Bunun yerine şunu kullanırsam [Char]:

instance Fooable [Char] where
  toFoo = FooString

GHC şikayet ediyor:

Illegal instance declaration for `Fooable [Char]'
   (All instance types must be of the form (T a1 ... an)
    where a1 ... an are type *variables*,
    and each type variable appears at most once in the instance head.
    Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Fooable [Char]'

Soru :

  • Neden bir tip sınıfının String ve örneğini yapamıyorum?
  • GHC fazladan bir bayrak eklersem bundan kurtulmama izin vermeye istekli görünüyor. Bu iyi bir fikir mi?

6
Bu, oy verdiğim ve favori olarak işaretlediğim türden sorular çünkü aksi takdirde yakın gelecekte soracağımı biliyorum;)
Oscar Mederos

3
Ekstra bayrakla ilgili olarak: GHC'ye güvendiğiniz ve bayrağın ne yaptığını anladığınız sürece muhtemelen iyi bir fikirdir. Yesod akla geliyor: Yesod uygulamalarını yazarken her zaman OverloadedStrings pragmasını kullanmanızı teşvik ediyor ve QuasiQuotes, Yesod yönlendirme kuralları için bir gerekliliktir. Derleme zamanında bir bayrak yerine {-# LANGUAGE FlexibleInstances #-}.hs dosyanızın en üstüne (veya başka herhangi bir pragma) koyabileceğinizi unutmayın.
Dan Burton

Yanıtlar:


65

Bunun nedeni ise Stringsadece bir tip diğer adıdır [Char]tür kurucusu sadece uygulama olan []tipine Charbu formun olacağını, böylece ([] Char). hangi formda değildir, (T a1 .. an)çünkü Charbir tür değişkeni değildir.

Bu kısıtlamanın nedeni, çakışan örnekleri önlemektir. Örneğin, diyelim ki bir tane var instance Fooable [Char]ve daha sonra birisi geldi ve tanımladı instance Fooable [a]. Artık derleyici, hangisini kullanmak istediğinizi bulamayacak ve size bir hata verecektir.

Kullanarak -XFlexibleInstances, temelde derleyiciye bu tür örnekleri tanımlamayacağınıza söz veriyorsunuz.

Neyi başarmaya çalıştığınıza bağlı olarak, bir sarmalayıcı tanımlamak daha iyi olabilir:

newtype Wrapper = Wrapper String
instance Fooable Wrapper where
    ...

4
Ben de gerçekten istediğimi iddia etmek adına söyleyelim instance Fooable [a]. Char toFooise fonksiyonun farklı davranmasını sağlamanın bir yolu var mı a?
John F. Miller

7
@John: Buna -XOverlappingInstancesizin verecek ve en spesifik örneği seçecek bir uzantı var. Ayrıntılar için GHC kullanıcı kılavuzuna bakın .
hammar

18

Klasik Haskell98 tip sınıflarının iki sınırlamasıyla karşılaşıyorsunuz:

  • örneklerde tür eş anlamlılarına izin vermezler
  • sırayla tür değişkenleri içermeyen iç içe geçmiş türlere izin vermezler.

Bu zahmetli kısıtlamalar iki dil uzantısıyla kaldırılmıştır:

  • -XTypeSynonymInstances

Eğer (gibi tip synoyms kullanmaya olanak sağlayan Stringiçin [Char]) ve:

  • -XFlexibleInstances

Bu T a b .., parametrelerin tür değişkenleri olduğu biçimdeki örnek türlerine ilişkin kısıtlamaları kaldırır . -XFlexibleInstancesBayrak örneği beyanının baş keyfi iç içe türü söz veriyor.

Bu kısıtlamaların kaldırılmasının bazen çakışan örneklere yol açabileceğini unutmayın; bu noktada, belirsizliği çözmek için GHC'nin sizin için bir örnek seçmesine izin veren ek bir dil uzantısı gerekebilir.


Referanslar ::


4

Esnek Koşullar çoğu durumda iyi bir yanıt değildir. Daha iyi alternatifler, String'i yeni bir türe sarmak veya şöyle bir yardımcı sınıf sunmaktır:

class Element a where
   listToFoo :: [a] -> Foo

instance Element Char where
   listToFoo = FooString

instance Element a => Fooable [a] where
   toFoo = listToFoo

Ayrıca bkz .: http://www.haskell.org/haskellwiki/List_instance


2

Bu yanıtlara ek olarak, kısıtlamaları kaldırmak konusunda rahat değilseniz, String'inizi bir sınıfın örneği olabilecek yeni bir türle sarmanın mantıklı olabileceği durumlar olabilir. Ödünleşim, kodunuzu sarmak ve açmak zorunda kalacağınız potansiyel çirkinlik olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.