4

Haskell を学ぶための演習として、独自の foldMap 関数を作成しようとしています。

現在はこんな感じ

class Functor f => Foldable f where
    fold    :: Monoid m =>             f m -> m
    foldMap :: Monoid m => (a -> m) -> f a -> m
    foldMap g a = fold (<>) mempty (fmap g a)

ただし、コンパイルすると、次のエラーが発生します

Could not deduce (Monoid ((f m -> m) -> fm -> m)) arising from use of 'fold'
from the context (Foldable f) bound by the class declaration for 'Foldable' at (file location)
or from (Monoid m) bound by the type signature for foldMap :: Monoid m => (a -> m) -> f a -> m at (file location
In the expression fold (<>) mempty (fmap g a)
In an equation for 'foldMap':
     foldMap g a = fold (<>) mempty (fmap g a)

このエラーでコンパイラが何を伝えようとしているのかわかりません。foldMap の何が問題なのか誰か教えてもらえますか?

4

2 に答える 2

10

たぶん、実際のソリューションで答えを出す必要があります:

これが可能な定義であることが明確になったことを願っています。

class Functor f => Foldable f where
    fold    :: Monoid m =>             f m -> m
    foldMap :: Monoid m => (a -> m) -> f a -> m
    foldMap g a = fold $ fmap g a

タイプをフォローする

アンドリューとリーはすでに高レベルの説明をしてくれましたが、別の見方をすることができるかもしれません:

この答えを得るために型に従ってみましょう:

がモノイドであり、ファンクタである関数f a -> mが必要です。さらに、一部からモノイドを取得するために使用できる関数があります - いいですね。mfg :: a -> ma

これで、いくつかの追加機能が得られます。

  • fold :: f m -> m私たち自身のクラスから
  • fmap :: (a -> b) -> f a -> f bファンクターからf

わかりました、今必要なのは、が であるf a -> m場合のみ、使用できます... ダン。amfold

しかし待ってください: aamを usingにすることはできますgが、は... dangaにパックされます。f

ちょっと待って: f aaf mを using fmap.... ding-ding-dingにすることができます

それではやってみましょう:

  • f af mます:fmap g a
  • その上で折り畳みを使用します:fold (fmap g a)

または使用$

foldMap g a = fold $ fmap g a

試すことができるように、何かを取得しましょう。

module Foldable where

import Data.Monoid

class Functor f => Foldable f where
    fold    :: Monoid m => f m -> m
    foldMap :: Monoid m => (a -> m) -> f a -> m
    foldMap g a = fold $ fmap g a

instance Foldable [] where
  fold []     = mempty
  fold (x:xs) = mappend x (fold xs)

これをSumと で使用した簡単な例を次に示し[1..4]ます。

λ> foldMap Sum [1..4]
Sum {getSum = 10}

私には問題ないようです。

于 2014-10-10T04:43:27.607 に答える
0

モノイドには と の 2 つの関数がmappendあり、の代わりにmempty使用できます。(<>)mappend

型クラスが機能するのは、コンパイラがデータの型に応じて関数の適切な定義を挿入するためです。(幸いなことに) 問題の関数を渡す必要はありません。

あなたが犯した間違いは、使用しているモノイド関数を不必要に渡すことです.

たとえば、次のようなリストに何かがあるかどうかをテストする関数を定義したとします。

isin :: Eq a => a -> [a] -> Bool
isin equalityFunction a list = any (equalityFunction a) list

不必要に を引数として渡そうとしましたがequalityFunction、型シグネチャが一致しません。

代わりに、定義する必要があります

isin :: Eq a => a -> [a] -> Bool
isin a list = any (== a) list

型クラスで定義されている等価関数の標準名を使用しEqます。

(<>)同様に、 orempty引数を渡す必要も、渡す必要もありません。

于 2014-10-09T21:35:09.867 に答える