2012-08-27 21 views
6

Tanıdığım çoğu OO dilinde, String'un toString yöntemi aslında yalnızca kimlik işlevidir. Ancak Haskell show çift tırnak ekler.Tırnak eklemeyen bir polimorfik "toString" işlevi var mı?

yüzden numaralar

f [0,1,2,3] -- "0123" 

ama Yaylı ekstra tırnak

f ["one", "two", "three"] -- "\"one\"\"two\"\"three\"" 

zaman ben gerçekten sona için beklendiği gibi çalıştığını bu

f :: Show a => [a] -> String 
f = concat . map show 

gibi bir işlev şey yazarsanız "onetwothree"'u isteyin.

Polimorfik olarak f yazmak istemiş olsaydım, bunu yalnızca Show kısıtlamasıyla yapmanın ve Örneğini Göster örneğini geçersiz kılmadan yapmanın bir yolu var mı (eğer mümkünse).

Kendi tip sınıf yaratmaktır ile gelebilir iyi:

class (Show a) => ToString a where 
    toString = show 

ve her şey için bir örneğini ekleyin?

instance ToString String where toString = id 
instance ToString Char where toString = pure 
instance ToString Int 
instance ToString Maybe 
...etc 
+0

Özelleştirilmiş bir "Gösterisi" (https://github.com/corsis/PortFusion/blob/ad63a006cff324667cca2316699e26a0078fbc02/src/Main.hs#L67) türü oluşturmak için 'newtype' yapısını kullanarak sona erdim 've' Read' örnekleri: https://github.com/corsis/PortFusion/blob/ad63a006cff324667cca2316699e26a0078fbc02/src/Main.hs#L67 –

+0

Ayrıca bkz. http://stackoverflow.com/questions/12102874/haskell-suppress-quotes -çevre-dizeleri-gösterildiğinde – sth

+0

'Show' sadece çift tırnak ekler değil unutmayın. Ayrıca satır sonları gibi karakterlerden kaçar. Örneğin, tek karakterli bir karakter olan "" \ n "', ", \, n" karakterleriyle dört karakterli bir dize olarak gösterilir. – sdcvvc

cevap

3

Bunu yapabilirsiniz: bu muhtemelen korkunç bir fikir olduğunu

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-} 

class Show a => ToString a where 
    toString :: a -> String 

instance Show a => ToString a where 
    toString = show 

instance ToString String where 
    toString = id 

Prelude> toString "hello" 
"hello" 
Prelude> toString 3 
"3" 

Not.

+0

Teşekkürler. Son sözlerini özellikle beğendim "Bu muhtemelen korkunç bir fikir." :) Bunu sağlamak için farklı dil uzantılarının gerçekte ne yaptığını açıklayabilir misiniz? –

+3

'FlexibleInstances' olmadan, tür sınıflarının üyeleri olarak çıplak tip değişkenlerinin bulunmasına izin verilmez. 'UndecidableInstances' olmadan, örneğin tür argümanlarından en az biri, çıplak bir tip değişkeni olmamalıdır. Bunlardan hiçbirinin olmaması, yukarıdaki ilk beyannameye izin vermez. 'OverlappingInstances' olmadan, yukarıdaki örneklerin her ikisini birden elde edemeyiz, çünkü açıkçası ilk örnek tüm gösterilebilir tipler için geçerlidir ve 'String' türden bir örnektir, yani çakışırlar. –

+0

Yorumunuz hakkında (muhtemelen) korkunç bir fikir olup olmadığına dair yorumunuz, örneklerin diğer modüllere sızması sorunu mu? –

2

Sen OverloadedStrings ile newtype kullanabilirsiniz:

{-# LANGUAGE OverloadedStrings #-} 

import   Data.ByteString.Char8  (ByteString) 
import qualified Data.ByteString.Char8 as B 

newtype LiteralString = LS ByteString 
instance IsString LiteralString where fromString = LS . B.pack 
instance Show  LiteralString where show (LS x) = B.unpack x 
instance Read  LiteralString where readsPrec p s = map (\(!s, !r) -> (LS s,r)) $! readsPrec p s 

hello :: LiteralString 
hello = "hello world" 

main :: IO() 
main = putStrLn . show $! hello 

çıkışı:


Normal durumda çift tırnak

hello world 
aslında yararlıdır geri bir gösterilen dize okurken Değerlerden gösterilen dize değerlerini açıkça sınırladığı için daha büyük ifadenin içeriği Diğer gösterilen türde:

x :: (ByteString, Int) 
x =  read . show $! ("go", 10) 
-- string value starts --^^-- ends 

y :: (LiteralString, Int) 
y =  read . show $! ("go", 10) 
-- string value starts --^  ^consumes all characters; read fails 
+0

Bunun en temel probleminin, yine de fonksiyonun çağrısını arayan kişiye bağlı olduğunu düşünüyorum. standart olmayan bir String tipini kullanmaları gerekir. –

+3

'show' ile ilgili asıl sorun, insanların güzel baskı/ayrıştırma amaçları için bunları kullanmasına karşı neler söyleyebilecekleri ne olursa olsun,' okunması 'ile güçlü bağları olduğunu düşünüyorum; varsayılan okuma davranışı. show = id' ve bu çift tırnak için neden gibi görünüyor. –

5

Pretty sınıfı ve onun ilgili türün Doc Show için gerekli davranışa sahip. Bağlantınız farklı bir kullanım durumunu gösterir; belki soruyu düzenleyebilir misin?

+0

Teşekkürler, bu sınıfı bilmiyordum. –

7

Sorununuzun temel nedeni, show gerçekten renderToText değil. Aynı değeri elde etmek için Haskell koduna yapıştırabileceğiniz veya read kullanarak aynı değere geri dönüştürebileceğin metin üretmesi gerekiyordu. Bu amaç için show "foo" = "foo", show "1" = "1" ve show 1 = "1" bilgi kaybından dolayı çalışmaz.

Eğer "foo" ve 1 almak için almak için "foo" uygulamak isterler operasyon "1"show dışındaki bir şeydir. show sadece bir Java-esque toString değil.

Daha önce buna ihtiyaç duyduğumda, kendi yeni tip sınıfımı yaptım ve bir sürü şey yaptım ve daha sonra bunu Show yerine kullandı. Örneklerin çoğu, show ile uygulandı, ancak özelleştirmek istediğim sadece String değildi, bu yüzden ayrı tip sınıf tamamen boşa değildi. Pratikte, aslında gerçekten ihtiyacım olan bir avuç türü vardı ve derleme hatalarım olduğu için onları eklemek çok kolaydı.

+0

Ben, cevabınız doğru değil. "Göster" in amacı, bir dizeye Haskell değeri vermektir. İzomorfik Okuma/Gösterme örneklerine sahip olma zorunluluğu yoktur - Haskell Raporu'na bakınız. Kuşkusuz, izomorfik Okuma/Gösterme örnekleri yararlıdır, ancak zorunlu değildir. Eğer serileştirmek istiyorsanız bunun yerine 'Binary' kullanmayı düşünün. –

+1

Bu doğrudur, ancak standart kütüphane örneklerinin (ve "türetme tarafından üretilenler") hepsi de Haskell sözdizimini kullandığından, "dizinin" üretildiği dizeler için hedef kitlenin Haskell programcıları olduğu oldukça açıktır. "Bu değer metnini, kullanıcılara gösterebileceğim şekilde biçimlendirmek" için tasarlanmamıştır. – Ben

İlgili konular