2

Haskell で独自の型を定義し始めたところですが、 http://www.haskell.org/haskellwiki/Typeのセクション 3 にある カードの表現に関する例が役に立ちました。やりたいことがあるのですが、どうすればいいのかわかりません。カードのアナロジーを使って説明しようと思います。

さまざまなカードのコレクションで作業したいと考えています。カードは常にCardValueとSuitを持つように修正するとしますが、標準コレクションと同様に、5番目のスーツ「Rubies」を持つデッキを許可したいとします。私は、Kind1 と Kind2 を取り、Kind1 と Kind2 からのスーツの結合を可能な限り持っている種類のカード Kind3 を定義し、Kind1 からのスーツのセットをカード値として定義できるようにしたいと考えています。また、ユーザーがスートの名前などを入力できるプログラムをコンパイルして、入力した種類のカードで標準的なカード操作を実行できるようにしたいと考えています。 私がやりたくないのは、限られた数の異なるデータ型を書き出すことです。なぜなら、さまざまな種類のカードがすべてどうなるかを前もって知らないからです

たくさんのリストと、物事がリストの要素であることを確認するためのたくさんのチェックを含むソリューションを想像することはできますが、書くのは悪夢であり、非常に非効率的だと思います。

動作しない疑似コードをいくつか書きましょう。ただし、上記の説明よりも、やりたいことのアイデアが得られるかもしれません。

-- this isn't real code!

type Suit = [String]
type CardValue = [String]

data (Card s v) = (Card s v) {suit :: (s :: Suit), value :: (v :: CardValue)}

usualSuit :: Suit
usualSuit = ["Club","Diamond","Heart","Spade"]

flowerSuit :: Suit
flowerSuit = ["Rose","Daisy","Poppy"]

もちろん、これがナンセンスであることはわかっています。また、コンパイル時にすべての型が定義されるという原則に反していると思います (これは良い原則であることがわかります)。

誰でも教えてもらえますか:

  • 私が説明しているようなことをする方法はありますか?
  • 同じことを達成するためのより良い方法はありますか?

また、リンクやキーワードを読んでみたいと思っていますが、プログラミング用語や Haskell についてもあまり知らないことに注意してください。

私は Haskell を使用してこれを行いたいと思っています。遅延評価と無限リストは私にとって非常に便利であり、そのためのコードを既に作成しています。

グーグルでいくつかの Haskell チュートリアルを調べてみましたが (私はまだ初心者です!)、役に立つものは見つかりませんでした。これはおそらく、検索する単語がわからないためです。

ありがとう

編集:やりたいことをうまく説明していないのではないかと心配しています。これは、エラーなしでコンパイルされる本物のコードで、何をしたいかを説明する注釈が付いています。

import Data.List

type Suit = String
type Value = Integer
type ListOfSuits = [Suit]
type ListOfValues = [Value]

data Deck = Deck {listofsuits :: ListOfSuits, listofvalues :: ListOfValues } deriving (Show)

sillyDeck :: Integer -> Deck
-- This is some function.  For example, we might have
sillyDeck n = Deck ["Heart","Spade"] [1..n]
-- Note that this defines infinitely many different decks

-- How should I define a card in sillyDeck n?  One option is
data Card = Card {suit :: Suit, value :: Value } deriving (Show)
-- but this doesn't reference the deck I'm using.  I could try
data Card2 = Card2 {suit2 :: Suit, value2 :: Value, deck2 :: Deck } deriving (Show)
-- but then
cardInWrongDeck :: Card2
cardInWrongDeck = Card2 "Cheese" 999 (sillyDeck 3)
-- is valid, when I'd hope for something like a type error.
-- Of course, I could write a function to check that each card is in the
-- deck it claims to be, and apply it regularly, but that's a horrible solution.

-- Is there a better way to do this?

うまくいけば、これも私のタイトルを説明しています: タイプ Deck のいくつかのデッキをパラメーターとして取るタイプ (CardOfType デッキ) を定義したいと思います。これはできないと思いますが、わかりません。

私がやりたいこと(基本的に、それぞれがオブジェクトのセットであるオブジェクトのセットを持つ)は基本的なことのように思えます-人々は以前に同様の問題に遭遇したに違いありません、そして私はいくつかの素晴らしい構造的な方法があることを望んでいますわからないことを整理する。

編集 2: Philip JF が GADT (= 一般化された代数データ型) に向けて私を指摘し、いくつかの読書を行ったことに基づいて、私が探していたものが「依存型」と呼ばれることに気付きました。したがって、私の元のタイトル「パラメーター付きの型」は、それほどばかげているようには聞こえません。これらは Haskell には存在しないようです。それらのシミュレーションについて述べている論文を見つけ、型の関数を明らかにサポートしている Ωmega について読んだことがあります。パラメータとして値を取る型を持つ言語が存在するかどうかはまだわかりません。

4

1 に答える 1

3

Haskell の型システムは、高度な機能を使用する意思がある場合はほとんど何でも実行できますが、Haskell を学習する初期の段階でこれらのほとんどを使用することはお勧めしません。あなたの場合、私はおそらくそのようにモデル化します

data Card s v = Card {suit :: s, value :: v}

次にスーツを次のように定義します

data UsualSuit = Club | Diamond | Heart | Spade deriving
data FlowerSuit = Rose | Daisy | Poppy

これは、あなたが望むことのほとんどを行います。たとえば、次のような複合スーツを定義するのは簡単です

data Rubies = Rubies
type UsualOrRubies = Either UsualSuit Rubies

これにより、静的なケースでのニーズが完全に解決されると思います。動的にスーツに入るユーザーがいる場合、事態はより複雑になります。1 つのオプションは、「stringly typed」にすることです。

type StringySuit = String

を使用して何かを行うことはできますが、問題のより大きな例を挙げない限り、ベースのソリューションGADTsの問題が何であるかはわかりません。String実際には、GADT を使用して効果的に「実行時に型を作成する」ことができますが、初心者にとっては混乱する可能性があります。

于 2012-12-20T02:45:21.673 に答える