Haskell 代数データ型の選択肢の中から選択する
-
13-09-2019 - |
質問
入力するとき X
と定義されている:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
そして私はそれが欲しいです Int
の中で X
1 がある場合は値、それ以外の場合は 0。
returnInt :: X -> Int
どのタイプかを判断するにはどうすればよいですか X
に対する議論 returnInt
は?
解決
ここでの点を明確にするために、X の意味の曖昧さを避けるためにデータ型を書き直させてください。
data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}
この定義では、X、I、B タイプは存在しません。X、I、B は type の値を作成するコンストラクター Sometype
。これらの型コンストラクターで構築された値の型を ghci に尋ねるとどうなるかに注目してください。
*Main> :t (I 5)
(I 5) :: Sometype
*Main> :t (B False)
(B False) :: Sometype
同じタイプに属します!!
X、I、B を使用して型を構築できるのと同じように、上記の他の回答で行ったように、パターン マッチングを使用して型を分解できます。
returnInt :: SomeType -> Int
returnInt (I x) = x -- if the pattern matches (I x) then return x
returnInt _ = error "I need an integer value, you moron" -- throw an error otherwise
パターンマッチングは次の順序で行われることに注意してください。値がある行のパターンと一致する場合、それより下の行のパターンは実行されません。
上記のように型を定義するときは、いわゆるレコード構文を使用することに注意してください (ここを見てください: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes )、そんな機能が無料で手に入るんです!!
たとえば、myInt の型を調べてみてください。
*Main> :t myInt
myInt :: SomeType -> Int
この関数が何をするのか見てみましょう:
*Main> myInt (I 5)
5
*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt
これはまさにその行動です returnInt
上記で定義されています。この奇妙なエラー メッセージは、関数が一致しない SomeType 型のメンバーを処理する方法を知らないことを示しているだけです。 (I x)
.
より一般的な構文を使用して型を定義する場合:
data SomeType2 = X String | I Int | B Bool
そうなると、素晴らしい記録機能が失われます。
エラー メッセージによりプログラムの実行が終了します。これは時々迷惑です。関数により安全な動作が必要な場合は、GBacon の答えがまさにそれを行うための方法です。について学びましょう Maybe a
値を返すか何も返さない必要があるこの種の計算に対処するには、それを入力して使用します (これを試してください: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe ).
他のヒント
パターンマッチングを使用します。
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
すべての可能なX
値のためのより柔軟な定義を使用します:
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
次に、あなたは maybe
使用することができますA>不履行特定のためにあなたがしたい-0を(これは semipredicate問題として知られている有効な値である場合があります):
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1
これとは対照的に、部分的な機能のリスク実行時例外ます:
*Main> let returnInt (I i) = i
*Main> :t returnInt
returnInt :: X -> Int
*Main> returnInt (B True)
*** Exception: <interactive>:1:4-22: Non-exhaustive patterns in function returnInt
あなたが本当にカエルを感じている場合は、あなたがMonadPlus
を使用することができます。
returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero
さらに多くの柔軟性を獲得するには:
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> returnInt (I 123) `mplus` returnInt (I 456) :: [Int]
[123,456]
このような関数が与えられます:
returnInt :: X -> Int
returnInt x = {- some integer -}
... x
のタイプは常にX
です。あなたが気にすることはx
はX
、I
またはB
型コンストラクタを使用するかどうかです。
の違いを教えてパターンマッチングを使用します:
returnInt :: X -> Int
returnInt (X _) = error "needed an Int, got a String"
returnInt (I { iVal = n }) = n
returnInt (B _) = error "needed an Int, got a Bool"