2016-02-10 2 views
7

LYAH読んで、私は、コードのこの部分につまずいた:高次多型は厳密な引数の順序を必要としますか?

newtype Writer w a = Writer { runWriter :: (a, w) } 

instance (Monoid w) => Monad (Writer w) where 
    return x = Writer (x, mempty) 
    (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v') 

一体最初の行でWriter wが何であるかを理解しようとしますが、私はこれは完全なタイプをされていない発見が、型コンストラクタの一種でMaybe String

ためMaybeのような1つの引数には、偉大なルックスが、何かのWriter'は、このように、スワップ型引数で定義されている場合は、最初のタイプ:

newtype Writer' a w = Writer' { runWriter :: (a, w) } 

Monadインスタンスを今すぐ実装できますか?このような何かが、何実際にコンパイルすることができます。

instance (Monoid w) => Monad (\* -> Writer' * monoid) where 

\* -> Writer' * monoidのアイデアはWriter wと同じです: 1型の引数​​が不足しているとの型コンストラクタ - この時間は最初の1。

+2

'Writer'は、' Monad'インスタンスを持つ明示的な目的のために定義します。スワップされた引数で定義する必要はありません。そして、あなたが決定可能な型チェックをしたいならば、そのような型レベル関数を書くことはできません。 –

答えて

9

これはHaskellでは不可能です。存在しないタイプレベルのラムダ関数が必要です。

を使用すると、型変数のreorderingsを定義するために使用できるタイプの同義語があります。

type Writer'' a w = Writer' a w 

ていますが(でもTypeSynonymInstances拡張子を持つ)、部分的に適用されるタイプの同義語のクラスのインスタンスを与えることはできません。

タイプ推論を犠牲にすることなく、タイプクラスのインスタンスでGHC:https://xnyhps.nl/~thijs/share/paper.pdfを使用するために、タイプレベルのラムダをGHCに追加する方法についての題目について書いています。

+0

それで、それはスカラーのラムダ型のためのものです! –

+0

実際、関連作業には、Scalaでの動作の例があります。 Scalaのトレードオフは、ほとんどの場合、型クラスを使用するときに型名を与える必要があることです。 – xnyhps

5

あなたがここに見ているのは、ハスケルの狭義のデザインの選択です。概念的に言えば、最初のパラメータを "除外"すると、Writer'タイプがファンクタであると言うのは完璧な意味を持ちます。そのような宣言を可能にするために、プログラミング言語構文を発明することができる。

ハスケルコミュニティは、彼らが持っているものは比較的単純で十分に機能するので、そうしていません。これは代替設計が不可能であるとは言えませんが、そのような設計を採用するには、次のようにしなければならないでしょう:

  1. 実際に使用するよりも複雑ではありません。
  2. 切り替えの価値がある機能または利点を提供します。

これは、Haskellコミュニティがタイプを使用する他の多くの方法に一般化します。タイプの区別として何かを表現する選択は、言語のデザインのアーティファクトに結びついていることがよくあります。多くのモナド変圧器はMaybeTのように、良い例です:

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } 

instance Functor m => Functor (MaybeT m) where ... 
instance Applicative m => Applicative (MaybeT m) where ... 
instance Monad m => Monad (MaybeT m) where ... 
instance MonadTrans MaybeT where ... 

それはnewtypeなので、これはMaybeT IO StringIO (Maybe String)同型であることを意味します。あなたは、同じ値のセット上の2つの「視点」として2種類を考えることができます。

  1. IO (Maybe String)はタイプMaybe Stringの値を生成IOアクションです。
  2. MaybeT IO Stringは、タイプStringの値を生成するアクションで、MaybeT IOアクションです。

視点の違いは、それらがMonad操作の異なる実装を暗示しているということです。 Haskellではこれは、以下の偏狭な技術的な事実に結びついている:1 String

  • は、最後のタイプのパラメータ(「値」)であり、他Maybe Stringです。
  • IOおよびMaybeT IOは、Monadクラスのインスタンスが異なります。

しかし、多分あなたはタイプIO (Maybe a)がそれに特定のモナドを有し、より一般的なIO aタイプのモナドは異なることを言うことができる言語の設計があります。その言語は、のデフォルトでどのMonadインスタンスをどのルールがプログラマにデフォルト選択を無効にするかを決定するためのルール)を一貫して区別するためには、の一部がと複雑になります。最終結果が私たちが持っているものよりも複雑ではないことを謙虚に賭けるでしょう。 TL; DR: Meh。

+0

ここで「偏狭」とはどういう意味ですか? – dfeuer

+2

ハスケルとそのコミュニティに特有です。カテゴリ理論の表記法の中には、 "* * B * functor"のようなものについて人々が話す異なる慣例があります。ダッシュは* A * B *のような表現の「穴」を指します。インスタンスMonoid m => Monad(Writer '_ m) 'またはインスタンスMonoid m => Monad(\ a - > Writer' a m)'などと言える言語の設計を考えてみてください。私たちがハスケルでこれを持っていない主な理由は、私たちがしていることはうまくいっているからです! –

関連する問題