-3

私はこれをグーグルで調べましたが、関連するものを見つけることができませんでした(多くの人が試してみたいと思うのは明らかなことであるように思われるので、私を驚かせました)。

私はこのようなことをしたい:

data Car = "ford" | "chevy"

言い換えれば、右側の値を一般的なものではなく、特定の値、つまり特定の文字列、特定の数値などにしたいのです。

これは可能ですか?どうすればいいのですか?

ありがとう。

編集: 私は探していません: データ 車 = フォード | シボレー

4

4 に答える 4

8

data Car = Ford | Chevy

データ コンストラクターは文字列ではありません。最初の文字の大文字化はオプションではないことに注意してください。Haskell では、データ コンストラクターは最初の文字を大文字にする必要があり、値の識別子の最初の文字は大文字ではない必要があります。

編集:

タイプの値を制限し、文字列として使用する方法は次のCarとおりFordですChevy

data Car = Ford | Chevy

carToString Ford = "Ford"
carToString Chevy = "Chevy"

次に、のような値を作成し、mycar = Fordその値を単に使用する文字列として使用したいときはいつでもcarToString mycar.

于 2012-09-24T23:32:02.710 に答える
5

あなたがやろうとしていることは、Haskell では直接可能ではありません。data Car = "ford" | "chevy"のサブタイプを作成しようとしているようStringです。すべてのCar値がs になりますが、すべての s が s になるStringわけではありません。試みている構文をより一般的に使用すると、サブタイプの無差別共用体である奇妙なタイプが作成されます (たとえば、.StringCardata Strange = 1 | "one" | '1'

Haskell の型システムにはサブタイピングがないため、これが直接機能することはありません。

Car型の値がsであることを実際に気にしない場合は、(Matt S によって提案されたように) をString使用できます。data Car = Ford | Chevy

type の値CarStrings であることを気にする場合、おそらくこれは、値を取る関数を適用できるようにしStringたいが、 oldを としてCar渡したくないためです。StringCar

必要な sのみであるCar型を作成することからそれを達成する別の方法は、型に加えて、指定された に対応するを提供する関数を作成することです。例えば:StringCarStringCar

data Car = Ford | Chevy

carStr :: Car -> String
carStr Ford = "ford"
carStr Chevy = "chevy"

次に、Car値を渡しCarたり、それらに対して操作を実行したりできます。(印刷などで) 実際に値が必要なときはいつでも、その値をString呼び出すだけcarStrです。

ただし、Showに変換できる型のクラスがあり、次のようなStringインスタンスを自動的に取得できます。Show

data Car = Ford | Chevy
    deriving Show

次に、関数はコンストラクターを、およびとしてshowレンダリングします。最初の文字が大文字になっているため、最初の文字とまったく同じではありません (データ コンストラクター名は大文字で始まる必要があり、派生インスタンスはコンストラクター名と一致します)。次のように、派生する代わりに独自のインスタンスを手動で作成できます。FordString "Ford"Chevy"Chevy"ShowShow

data Car = Ford | Chevy

instance Show Car where
    show Ford = "ford"
    show Chevy = "chevy"

しかし、非常に多くのShowインスタンスがレンダリングする値に対して正確な Haskell 構文を生成するため、可能な限りこれから逸脱しないことが最善であると考える傾向があります。しかし、両方の世界を最大限に活用し、自動派生Showインスタンスを使用できるため、データ コンストラクターとそれらが生成する文字列の間の対応を手動で設定する必要がなく、必要特定の文字列を生成する別の関数を使用できます。

import Data.Char

data Car = Ford | Chevy
    deriving Show

carStr :: Car -> String
carStr = map toLower . show
于 2012-09-25T00:39:17.660 に答える
4

Strings を使用することは非常に重要であるように思われますが、タイプ セーフが必要です。文字列は本質的にタイプ セーフではありません。抽象データ型タイプ セーフであり、慣れれば気に入るはずです。

利点の 1 つは、ユーザーが任意の大文字 (16 または 32 の可能性) を使用できるようにすることですが、内部的には表現が 1 つしかないため、一度データを読み込めば、データの使用は高速で効率的です。内部で文字列を使用すると、プログラムが使用されている Car に依存するたびに、より複雑な大文字と小文字の文字列チェックを永久に行うことになります。

データ型を内部でのみ使用している場合`Car、文字列はまったく必要ないため、文字列を使用する唯一の理由は入力と出力を処理することです。型安全性を確保し、文字列を使用して入力/出力を処理する方法を次に示します。コンパイル後、抽象データ型のデータ表現は非常に小さいため、文字列よりも高速に実行されます。

data Car = Ford | Chevy
  deriving (Read,Show,Eq)

これで、同等性を読み取り、表示し、チェックできるようになりました。これにより、次のことが可能になります

read "Ford" -- gives Ford
show Chevy  -- gives "Chevy"
Ford == Chevy -- gives False
read "GM" -- gives an exception. oops.

しかし、おそらく read と show よりも便利でしょう

getCar :: String -> Maybe Car
getCar xs = case toLower xs of
   "ford"   -> Just Ford
    "chevy" -> Just Chevy
    _       -> Nothing

これは素晴らしいことです。なぜなら、例外をスローしてプログラム全体をクラッシュさせることなく、エラー チェックに簡単に使用でき、ユーザーは必要な大文字を使用できるからです。些細な例として、次のように書くことができます

feedback :: Maybe Car -> String
feedback Nothing = "Please enter a valid car. Why not use one of America's favourite brands? Ford or Chevy"
feedback (Just Ford) = "Thanks for choosing Ford."
feedback (Just Chevy) = "Thanks for choosing Chevy"

あなたも必要です

ungetCar :: Car -> String
ungetCar Ford  = "ford"     -- or you could use "Ford"
ungetCar Chevy = "chevy"    -- or you could use "Chevy"

使用するかどうかはあなた次第"ford"です"Ford"が、出力のためだけにチェックするためにこの文字列を内部的に使用していない"Ford"ので、通常のテキストで使用する大文字を使用することもできます。

ungetCar = show

今あなたのコードであなたは書くことができるでしょう

... if car == Ford then .... else .....

それ以外の

... if (map toLower carString) == "ford" then ... else

型安全性の利点は、関数がCarデータ型を使用する場合、ユーザーが有効な車、フォードまたはシボレーを入力したことを問題なく想定できることであり、「フォード」ではない文字列が原因でクラッシュしたりエラーを起こしたりすることはありません。または「シボレー」。これにより、すべてのエラー チェック コードが を初めて使用する場所に移動しますgetCar。文字列を使用し、コードを堅牢にしたい場合、車を使用するすべての関数は、指定された車が有効であることを確認し、そうでない場合は例外をスローする必要があります。その後、非常に多くのプロセッサーサイクルを無駄にしており、めんつゆの扱いでエラー。data Car = Ford | Chevy安全性、スピード、利便性を備えています。

抽象データ型を使用すると、無効なデータを 1 回だけチェックしながら、防御的にプログラミングできます。それだけで、あなたはそれを好むべきです。また、明確で、きれいで、簡単です。

後で別の車を追加する場合

データ 車 = フォード | シボレー | シボレー | GM

数ビットのコードを更新するだけです (例: getCar)。

于 2012-09-25T06:36:05.203 に答える
2

あなたが達成したいことは本当に明確ではありません。どこでも使用できる型が必要なように聞こえますStringが、同時に、文字列が取り得る可能な値のサブセットにしかなり得ません。しかし..それは本当にどういう意味ですか?

たとえば、これらの機能の両方を許可する必要がありますか?

reverseCar :: Car -> Car
reverseCar = reverse

idCar :: Car -> Car
idCar = map id

調べてみると、 がreverseCar実際には ではなくなった出力値を生成することがわかりますCar。しかしidChar、実際には何も変更されないため、出力は依然としてCar. しかし、それを自動的にチェックできるコンパイラを構築することは不可能です。

したがって、どこでも使用できる型を持つことはできずString、同時に、機能するStringが非Car値になる関数を適用できなくなります。

以下を除いて:

data Char = Ford | Chevy

あなたのオプションは、タイプエイリアスといくつかのヘルパー関数を使用することです:

type Car = String

ford :: Car
ford = "ford"

chevy :: Car
chevy = "chevy"

これにより、タイプミスを防ぐことができ、 a を使用できる場所ならどこでも afrodを使用できるようになります。ただし、無効な型を作成するような関数も適用できることを意味します。CarStringreverseCar

さらに一歩進んで、newtype ラッパーを使用することもできます。

newtype Car = Car { carToString :: String }

ford :: Car
ford = Car "ford"

chevy :: Char
chevy = Car "chevy"

次に、 a を安全に使用できる一連の信頼できる関数を定義し、Carそれらの関数のみをエクスポートしますが、Carデータ コンストラクターはエクスポートしません。reverseそれは、人々が のような関数を直接適用することを妨げCarます。代わりに、安全な関数carToStringだけに制限したくないことをコンパイルに伝えるために使用する必要があります。Car

これもおそらくあなたが望むものではありません。しかし、自分が何を望んでいるのかを正確に説明しようとすればするほど、自分が望んでいることが一貫していない、または不可能であることに気付くでしょう。

不可能とは、'Haskell では不可能' という意味ではなく、'停止問題を不可能に解決する必要がある' という意味です。

あなたが与えた例はInteger、リテラル3.567を許可しないことです。それはさまざまな問題を混同しています。データ型自体にはInteger3.567 を表現する方法がありません。次のようになります。

data Integer = I Int32 | J [Digit]

つまり、マシンの int で表現できる小さな整数か、数字のリストです。したがって、型自体は小数点の使用を明示的に禁止しています。よく似てる

data Car = Ford | Chevy

「リンゴ」を表現するのを防ぎます。

ソースコードの数値リテラルを値に変換するという問題もありIntegerます。(3.567 :: Integer) と書くと、これは本質的に省略形であり、次のように展開されます。

(fromRational (3567 % 100)) :: Integer

次のようなエラーが表示されます。

No instance for (Fractional Integer)
      arising from the literal `3.567'

Integerしかし..それは、リテラル値をorのような型に変換するプロセスですDoubleIntegerDoubleがサブタイプである一般的な数値型はありません。

quasi-quoter を使用して同様のことを行うことCarができるため、次のように記述できます。

myCar :: Car
myCar = [car| ford |]

そして、それは受け入れられますが、これは拒否されます:

notMyCar :: Car
notMyCar = [car| apple |]

しかし今、私たちは本当に深いところから外れてしまい、あなたが望んでいたものに近づくことはできませんでした..あなたが何を望んでいるのかはまだかなり不明です

于 2012-09-25T04:58:21.727 に答える