2016-10-26 17 views
3

型の制約が型エイリアスでどのように機能するかを理解しようとしています。RankN型の別名混乱のタイプ

type NumList a = Num a => [a] 

そして、私は次の機能があります:

addFirst :: a -> NumList a -> NumList 
addFirst x (y:_) = x + y 

この関数は、次のエラーで失敗します。

Type.hs:9:13: error: 
    • No instance for (Num a) arising from a pattern 
     Possible fix: 
     add (Num a) to the context of 
      the type signature for: 
      addFirst :: a -> NumList a -> a 
    • In the pattern: y : _ 
     In an equation for ‘addFirst’: ad 

明らかであるまずは、私は次のタイプの別名を持っていると仮定しましょう。この問題は、すでにここで説明:

Understanding a rank 2 type alias with a class constraint

そして、私たちが動作するように、前の例では動作しません。なぜ、このようなタイプの別名のため{-# LANGUAGE RankNTypes #-}を必要とする理由私は理解しています。次の例は、(GHC 8に)罰金コンパイルしかし、なぜ私が理解していないことです。もちろん

prepend :: a -> NumList a -> NumList a 
prepend = (:) 

私は間違った値を渡ししようとした場合、それはghciに失敗:

λ: prepend 1 [] 
[1] 
λ: prepend "xx" [] 

<interactive>:3:1: error: 
    • No instance for (Num [Char]) arising from a use of ‘prepend’ 
    • When instantiating ‘it’, initially inferred to have 
     this overly-general type: 
     NumList [Char] 
     NB: This instantiation can be caused by the monomorphism restriction. 

はタイプのように思えます

first :: NumList a -> a 
first = head 
:実行時に遅れ:(

また、いくつかの簡単な、コードの同じ部分であるように思わはコンパイルされません型チェック

そして、次のエラーが発生します。

Type.hs:12:9: error: 
    • No instance for (Num a) 
     Possible fix: 
     add (Num a) to the context of 
      the type signature for: 
      first :: NumList a -> a 
    • In the expression: head 
     In an equation for ‘first’: first = head 

誰かがここで何が起こっているか説明できますか?私は機能の種類のチェックの有無にある程度の一貫性があると思います。

+2

'Num a => a'を関数' NumDict a - > a 'と考えると、それはすべて明らかでなければなりません。 –

+0

@Alecが提案した質問に既にリンクしていましたが、2番目の答え(luquiによるもの)が受け入れられているものよりもおそらくもっと明確であることを指摘する価値があります。なぜ 'prepend'が動作し、 (要するに、コンパイラは、シノニムが署名の最も右の位置にある場合、コンパイラはその制約をあなたが望むところに移動することができます)。ちなみに、 'prepend'の使用例には、' Num a => a - > [a] - > [a] '関数が期待しているものと全く同じように、奇妙なものや遅延したものはありませんする。 – duplode

+0

はい、リンクされた質問に対するluquiの答えは正確に関連しています。 –

答えて

1

Seems like type type checking delayed at runtime :(

実際はありません。ここでは、のファイルをロードした後にghci にタイプエラーが発生するため、少し驚くかもしれません。しかし、それは説明することができます:ファイル自体は完全に良いですが、それは意味するものではありませんすべてそれで定義された関数を使用して構築することができる式は型がよくなります。

上位ランクの多型は、それとは関係ありません。例えば(+)はプレリュードで定義されていますが、GHCiの中2 + "argh"を評価しようとした場合、あなたはあまりにも型エラーが発生します:

No instance for (Num [Char]) arising from a use of ‘+’ 
In the expression: 2 + "argh" 
In an equation for ‘it’: it = 2 + "argh" 

さて、問題はfirstであるか見てみましょう:それは与えられたと主張していますa NumList a、それはaを生成することができますが、質問はありません。しかし、我々は細い空気からNumList aを構築する方法を知っています!実際、Num aという制約は、0aであり、[0]が完全に有効なNumList aになることを意味します。firstは、その後、受け入れられた場合すべて種類が生息することになることを意味している:特にVoid

first :: NumList a -> a 
first = head 

elt :: a 
elt = first [0] 

を過ぎ、次のようになります。

argh :: Void 
argh = elt 

確かにカワイイ!

+0

>は、そこに定義されている関数を使用して構築できるすべての式が適切に型付けされることを意味するわけではありません。 ええ、それは良い点です。私はいくつかの思考と観察の誤りの後でのみ理解した。 – Shersh