8

私がよく知っているほとんどの OO 言語ではtoString、a のメソッドStringは実際には恒等関数にすぎません。しかし、Haskellshowでは二重引用符を追加します。

したがって、次のような関数を書くと

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

数値に対して期待どおりに機能します

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

しかし、文字列は余分な引用符で終わります

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

本当に欲しいとき"onetwothree"

ポリモーフィックに書きたい場合f、制約のみで、String の Show インスタンスをオーバーライドせずにそれを行う方法はありShowますか (それが可能であれば)。

私が思いつく最善の方法は、独自の型クラスを作成することです。

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

すべてのインスタンスを追加しますか?

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

4 に答える 4

8

あなたの問題の根本的な原因は、そうでshowはないことだと思いますrenderToText。Haskell コードに貼り付けて同じ値を取得したり、 を使用して同じ値に変換したりできるテキストを生成することになっていますread

と は情報を失うため、その目的にshow "foo" = "foo"は機能しません。show "1" = "1"show 1 = "1"

"foo"to get"foo"および to 1getに適用できる操作"1"は、 以外のものshowです。showただJava風ではありませんtoString

以前にこれが必要だったとき、私は実際に独自の新しい型クラスを作成し、そのインスタンスをたくさん作成してから、Show. ほとんどのインスタンスは で実装されてshowStringましたが、カスタマイズしたかったのは 1 つだけではなかったので、個別の型クラスが完全に無駄になることはありませんでした。実際には、インスタンスが実際に必要な型はほんの一握りしかなく、コンパイル エラーが発生したときにそれらを追加するのは非常に簡単でした。

于 2012-08-28T02:39:05.690 に答える
5

Prettyクラスとそれに対応する型にDocは、Show に必要な動作があります。ただし、リンクは別のユースケースを示しています。多分あなたは質問を編集できますか?

于 2012-08-28T00:45:18.003 に答える
3

あなたはこれを行うことができます:

{-# 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"

これはおそらくひどい考えであることに注意してください。

于 2012-08-28T00:21:44.187 に答える
2

newtypeで使用できますOverloadedStrings

{-# 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

出力:

hello world

通常の場合の二重引用符は、表示されている文字列値を他の表示されている型の値から明確に区切るため、表示されている文字列をより大きな式のコンテキストで読み取るときに実際に役立ちます。

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
于 2012-08-28T00:31:52.687 に答える