0

次のコードでは、関数 storePhone が Int を保存する電話番号の種類 (HomePhone または WorkPhone) を指定するにはどうすればよいですか?

type HomePhone = Int
type WorkPhone = Int

data Phone = HomePhone
           | WorkPhone

storePhone :: int -> Phone 
storePhone num = num

main :: IO ()
main = print $ storePhone 12345678

この質問は、私が行っているサイド プロジェクトに対する質問の簡略版です。ファイルを関連するデータ型に解析するモジュールがあります (サンプルの電話型のように)。すべてのデータは Double ですが、セマンティックな意味が異なります。別のモジュールには、データを使用するメソッドがあります。各メソッドは、引数としてデータ型 (別名 HomePhone、WorkPhone) の異なる順列を取ります。HomePhone と WorkPhone のデータ型、さらには newtype を作成することもできましたが、データを使用するメソッドがパターン マッチングなどでごちゃごちゃに見えてしまいます。それで、データ型(別名電話)を単純化して、もう少しエレガントでタイプセーフにすることができるかどうか疑問に思っていました。乾杯!私は次のことをするべきだと思いますか?

type HomePhone = Int
type WorkPhone = Int

data Phone = HomePhone HomePhone 
           | WorkPhone WorkPhone 
4

2 に答える 2

4

sepp2kはあなたの質問に非常によく答えたと思いますが、そもそもなぜあなたが問題を抱えていたと思うのかを説明しようと思います。型と値の間、および型コンストラクターと値コンストラクターの間には違いがあります。

Phone = Phone

この例では、左側がタイプで、右側が値です。タイプと値の両方に同じ名前を付けることができることに注意してください。コンパイラは、あなたが何を意味するのかを理解します。基本的に、型宣言とデータ宣言では型を意味し、関数の実装では値を意味します。

Phone = NoPhone
      | Phone Int

この例でNoPhoneは、は値であり、右側Phoneは値コンストラクターです。これは、型の値Intを使用して値を作成するためです。左側はまだタイプです。

Container a = NotEmpty a
            | Empty

この例でContainerは、は型コンストラクターです。これは、型Intを取得するためにこのような型を指定できるためです。この場合は、型になりContainer Intます。Emptyは値でありNotEmpty、値コンストラクターです。これは、たまたま選択したタイプの値を取ります。そのタイプをa呼び出して、タイプTの値を生成しますContainer T

あなたの例では、タイプと値の概念を混ぜ合わせています。

type HomePhone = Int
type WorkPhone = Int

これは、HomePhoneWorkPhoneはタイプの単なる異なる名前であることを示していますInt

data Phone = HomePhone
           | WorkPhone

これは、タイプのすべてがPhoneHomePhoneまたは値のいずれかを持っていることを意味しますWorkPhone。重要なのは、これらの値は、前に宣言した同じ名前のタイプシノニムと同じではないということです。

storePhone :: int -> Phone

これは、storePhoneがtypeの値を取り、typeIntの値を返すことを示していますPhone

storePhone num = num

これは問題だ。この行では、numは型の値ですが、numを返します。型宣言で、型の値、つまり値または値のいずれかIntを返すと言っただけです。ばかげたくても、型宣言に準拠している場合は、次のことができます。PhoneHomePhoneWorkPhone

storePhone num = if num > 0 then HomePhone else WorkPhone -- silly, but compiles :)
于 2013-02-09T13:59:16.320 に答える
4

現在の形式では、このPhone型は電話番号を格納できません。どちらもゼロの引数を取るため、何も格納できない 2 つのコンストラクターがあります。コンストラクターの名前が前に定義した型名と等しいという事実は、何の意味もありません。

あなたはおそらく次のようなことを意図していました:

type PhoneNumber = String -- Storing phone numbers as ints is a bad idea

data PhoneType = HomePhone
               | WorkPhone
                 deriving Show

data Phone = Phone PhoneType PhoneNumber
             deriving Show

storePhone :: PhoneNumber -> PhoneType -> Phone
storePhone number typ = Phone typ number

main :: IO ()
main = print $ storePhone "12345678" HomePhone
于 2013-02-09T12:12:10.243 に答える