私はHaskell多型に関する質問があります。Haskellは多重定義の多型をどのように扱いますか?
私が学んだように、多型の2種類があります。
パラメトリック:あなたが入力タイプを指定しないでください。
例:
functionName :: [a] -> a
オーバーロード:命令型プログラミングのように、すなわち、同じ機能に異なる引数を渡します。
私の問題は、次のとおりです。どのようにHaskellはをオーバーロードを処理しますか?
私はHaskell多型に関する質問があります。Haskellは多重定義の多型をどのように扱いますか?
私が学んだように、多型の2種類があります。
パラメトリック:あなたが入力タイプを指定しないでください。
例:
functionName :: [a] -> a
オーバーロード:命令型プログラミングのように、すなわち、同じ機能に異なる引数を渡します。
私の問題は、次のとおりです。どのようにHaskellはをオーバーロードを処理しますか?
Haskellでのオーバーロードは、型クラスを使用して行われます。たとえば、あなたがInt
を返す関数foo
をオーバーロードしたいとしましょう:
class Fooable a where
foo :: a -> Int
instance Fooable Int where
foo = id
instance Fooable Bool where
foo _ = 42
はしかし、彼らはほとんどの言語で見られるオーバーロードメカニズムよりも強力です。たとえば、あなたが戻り値の型にオーバーロードすることができます。より多くの例については
class Barable a where
bar :: Int -> a
instance Barable Int where
bar x = x + 3
instance Barable Bool where
bar x = x < 10
、Haskellではpredefined type classesを見ています。
ハスケルは、アドホック多型にtype classesを使用しています。
関数の型シグネチャを元の型クラスに指定し、その関数の複数インスタンスを作成します。したがって、hammarの例ではがと多相であり、それぞれのインスタンスで指定された型(例:Fooable Bool)がaの型(この場合はaはBool)であると考えることができます。したがって、関数fooをBool値で呼び出すと、Bool値のFooableのインスタンスが呼び出されます。
ところで、あなたはタイプクラスに複数の関数を置くことができ、定義された他の関数に関しても関数を定義することができます。
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
それはここでは明らかではないかもしれませんが、あなたは、式のインスタンスを定義した場合、あなただけの彼らはお互いの観点から定義されているので、両方とも、==または/ =をない定義する必要があります。
、ので、あなたは、あなたが取得しているDuplicate type signature
エラーを与えるだろう
split :: String -> [String] -- splits on whitespace
split :: Char -> String -> [String] -- splits on the given character
split :: [Char] -> String -> [String] -- splits on any of the given characters
split :: (Char -> Bool) -> String -> [String] -- splits using a function that tells you when
てみてください。
Haskellは過負荷に、このタイプのを行いませんし、Haskellのプログラマは、これらの異なる名前を与えるだろう:Haskellは私はあなたがについて尋ねていると思うの過負荷の種類を許可していません
words :: String -> [String] -- splits on whitespace
splitOn :: Char -> String -> [String] -- splits on the given character
splitsOn :: [Char] -> String -> [String] -- splits on any of the given characters
splitWith :: (Char -> Bool) -> String -> [String] -- splits using a function that tells you when
理由をそれが真にあなたがそれなしではできない何かをすることを許さないということであり、より高度な種類の過負荷を行うことはほとんど不可能になります。ハスケルのオーバーロードは確かに非常に強力なツールです。タイプクラスとコンストラクタークラスについて調べてみましょう。 String
= [Char]
、およびHaskellのプログラマはコードの再利用を愛しているので
実際、彼らは書くことがはるかに可能性が高いと思います。ここでは
words :: String -> [String] -- splits on whitespace
splitOn :: Eq a => a -> [a] -> [[a]] -- splits on the given item
splitsOn :: Eq a => [a] -> [a] -> [[a]] -- splits on any of the given items
splitWith :: (a -> Bool) -> [a] -> [[a]] -- splits using a function that tells you when
Eq a
は、どこHaskellは許可しないのオーバーロードのようなものの一例ですsplitOn
は、項目が等しいかどうか比較することができる限り、リストを分割することができます(つまり、Haskellでは独自の独自性を定義できます)。これを使用して文字列を分割することもできますし、例えば文字列のリストを分割することもできますが、2つの関数が同じかどうかをチェックすることができないため、関数のリストを分割することはできません。 splitWith
は、他のほとんどのデータと同じように関数を扱えるようにするHaskellの例です。引数として渡すことができます!
[注1:words
はsplitWith
が若干異なるtypesignatureで図書館であり、標準機能である。]
[注2:あなたが実際にこれらの関数を作成したい場合は、ここに方法は次のとおりです。
splitWith isSplitter list = case dropWhile isSplitter list of
[] -> []
thisbit -> firstchunk : splitWith isSplitter therest
where (firstchunk, therest) = break isSplitter thisbit
-- words = splitWith isSpace -- not needed, standard function from the Prelude
splitOn c = splitWith (== c) -- notice I passed == in an argument!
splitsOn chars = splitWith (`elem` chars)
あなたが似何かを行うことができますが、
]
は基本的にオーバーライドは、Haskellのではかなり異なっています。
I.選択された答えとしてクラスを使用します。
class YesNo a where
yesno :: a -> Bool
あなたは、インスタンスを使用して、それを実装する必要があり、その後、あなたはこのようにそれを使用することができます:
> yesno $ length []
False
> yesno "haha"
True
> yesno ""
False
> yesno $ Just 0
True
> yesno True
True
ghci> yesno EmptyTree
False
> yesno []
False
> yesno [0,0,0]
True
http://learnyouahaskell.com/making-our-own-types-and-typeclasses
II。以下のような、型コンストラクタのパターンマッチングを使用します。
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
surface :: Shape -> Float
surface (Circle _ _ r) = pi * r^2
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)
、その後、あなたは、このようにそれらを使用することができます。
> surface $ Circle 10 20 10
314.15927
> surface $ Rectangle 0 0 100 100
10000.0
http://learnyouahaskell.com/making-our-own-types-and-typeclasses
III。ここで
に名前を付け、あなたは
AD-を組み合わせた簡単な例を持ってsepatateモジュールに「oveloaded」機能を持っていますが、インポート名または修飾されたインポートの前に付ける必要があります。 (オーバーロード):異なるタイプの異なる動作(Haskellタイプのクラスを使用)で同じ機能です(Haskellタイプのクラスを使用)。
パラメトリック多形:異なるタイプの同じ動作(パラメータ化されたタイプの関数を使用)。 原則として、型は関係ありませんが、型クラスを使用して 許容型を制限しています)。
コード:
import Data.Char
class MyTypeFamily t where
f1 :: t -> Int
f2 :: t -> Int
instance MyTypeFamily Int where
f1 x = x*x
f2 x = x+x
instance MyTypeFamily Char where
f1 x = (ord x) * (ord x)
f2 x = (ord x) + (ord x)
instance MyTypeFamily Bool where
f1 x
| x = 10
| otherwise = 10
f2 x
| x = 100
| otherwise = -100
-- ...............................................................
-- using f1, f2 as "overloaded" functions ("ad-hoc polymorphism)
-- (the algorithm for f1, f2 is chosen depending on their type)
--
-- using fun as polymorphic (parametric polymorphic function)
-- the algorithm of fun is always the same but it works on
-- different types
fun :: (MyTypeFamily t) => t -> Int
fun x = (f1 x) + (f2 x)
-- ...............................................................
-- ...............................................................
main = do
print $ fun 'J'
print $ fun True
print $ fun False
print $ fun (8 :: Int)
@Zach:オーバーロードは確かに多型の形と考えられています。参考:ウィキペディアの[Ad-hoc polymorphism](http://en.wikipedia.org/wiki/Ad-hoc_polymorphism)あなたの質問の第2部分であなたが何を指しているのか分かりません。明確にしていただけますか? – hammar
私は 'class Barable'を使用しようとしています。整数 '5'に等しい変数xがあるとします。 'bar x'は動作しませんでした。仕事の場合には、「8」か「false」を返すでしょうか?あいまいな例です。 – Jaider
@Jaider:型は、通常、型の注釈を使用して強制することはできますが、型が使用されているコンテキストから推論されます。 'bar 5 :: Int'または' bar 5 :: Bool'を試してください。 – hammar