2015-10-14 8 views
11

wiki pageは、どちらのクラスもコンテナ操作を扱い、Foldableはコンテナのクラスとしてfoldrを定義し、Functorはfmapです。FoldableとFunctorはなぜ別のクラスですか?

ただし、FoldableであるタイプとFunctorsであるタイプの基本的な違いは何ですか?この区別で

ウィキヒント:

クラス[折り畳み式]は設定またはStorableVector

などのコンテナ

を可能にするためにのFunctorスーパークラスを必要としません。しかし、私はまだ、なぜわからないんだけど私が正しく解釈している場合、Setを別のセットを取得するためにマップすることができませんでした。

+1

@Bergi Whoopsは急いで書いていましたが、リンクを追加しました – corazza

答えて

12
Foldable

Functor提供(又はを低減する)折り畳まれは、それぞれ、上にマッピングすることができる構造を持つタイプのための2つの別個の抽象。

A列挙して組み合わせることができる折り畳み式ホールド値。 Foldableはリスト(toList :: Foldable f => f a -> [a])に変換できるものと考えることができます。代わりに、Foldablesを値が単調に結合できる構造体と考えることができます:(Foldable t, Monoid m) => (a -> m) -> t a -> m(もちろん、これを列挙する能力が必要です)。

Functorは、構造体(fmap :: (a -> b) -> (f a -> f b))が保持するaに関数(a -> b)を "持ち上げ"できるようにする構造体です。 fmapは、マッピングされる構造を保持する必要があります。ツリーは前後に同じ形状でなければならず、リストの要素数は同じ順序で同じでなければならず、Nothingは何かに変換できません。一方、折り畳み式はこの構造を保存する必要はありません。全体のポイントは、構造を破棄して新しいものを作り出すことです。

Wikiは、タイプクラス制約をfmapに指定する方法がないという事実を指します。 fmap :: (Ord a, Ord b) => (a -> b) -> Set a -> Set bは、制約がないクラス、fmap :: (a -> b) -> f a -> f bによって定義されたタイプで統一されません。これにより、Setのインスタンスは書き込めません。

しかし、これは単なる言語実装の問題であり、セットについてのより深い数学的な記述ではありません。 FoldableがFunctorスーパークラスを持たない本当の理由は、単にthere are Foldable instances which are not Functor instancesです。


  1. 「ホールド」ビット緩んでいるとProxy s aがゼロのを保持"Functors are containers"意味で解釈されることが意図され、Identity a一保持し、Maybe ab -> a|b|のを保持し、ゼロまたは1つ保持し、及びそうです。
8

xs :: Set Intがあり、その上に関数putStrLnをマップしたいとします。 IO()にはOrdインスタンスがないため、これは問題になります。そのため、これらのアクションを結果セットに挿入する方法を見つける方法はありません。 fmapのタイプは、Functorのタイプ引数に制約の余地がありません。

IOは、Functorの例を示しますが、foldMapに意味のある方法はありません。

FoldableFunctorが一緒になって、いずれかよりも大きな電力を与えることに言及する価値があります。

+0

これらのアクションを結果セットに挿入する方法を知るにはなぜOrdが必要ですか? 'Eq'だけが必要なのではないでしょうか?例えば、' == 'は任意の2つの' IO() 'に対して常に' False'になります。 – corazza

+0

@jcora、 'Eq'だけを使って効率的な*セットを実装することは不可能です。 'IO'の' Eq'の仮のインスタンスを作ることは、 '=='が意味することについてプログラマーが持つすべての期待を破ります。 – dfeuer

+0

ああ、もちろん、物事の実用的な側面を忘れた... – corazza

5

Functor typeclassは要素の種類に制約があるものに対してfmapを許可しません。 SetOrdが必要であり、StorableVectorStorableが必要です。

GHCのConstraintKinds拡張子を使用してのようなもの「制約ファンクタ」を表現することができる:

{-# LANGUAGE ConstraintKinds, 
      FunctionalDependencies, 
      MultiParamTypeClasses #-} 

import GHC.Exts (Constraint) 
import Data.Set (Set) 
import qualified Data.Set as Set 

class ConstrainedFunctor c f | f -> c where 
    cfmap :: (c a, c b) => (a -> b) -> f a -> f b 

instance ConstrainedFunctor Ord Set where 
    cfmap = Set.map 

をしかしFunctorが最初に登場したときに、この機械は、周りではなかったです。

さらに、Functorは、「形状を保持する」と考えられるが、例えば、 Set上のマッピングは、そのサイズを変更する可能性があります。

7

SetおよびStorableVectorは、ファンクタです。関数を実際にマップすることができます。

しかし、のいずれも、種類の機能はありません。たとえば、数字のStorableArray(+)をマッピングすることはできません。これは一連の関数を提供し、これらは格納可能ではありません。

したがって、これらのファンクタは、Haskのすべてではなく、特定のクラスの種類を含むサブカテゴリのみの(エンド)ファンクタです。これはHaskell98で表現することはできませんが、実際には拘束型の出現とともにまもなく可能になっただけです。See this example

instance Functor Set Ranking Ranking where 
    fmap = constrainedFmap Set.map 

実際に、あなたはいくつかの巧妙なGADT tricksを使用する場合Haskでモナドを形成も設定します。しかし、これはすべてのFoldableコンテナでは不可能であるため、標準ライブラリはFunctor f => Foldable fを必要としません。

関連する問題