Haskellで多変量関数を作成しようとしています。この回答を使用して、基本的な関数を作成しました。関数のコードは次のとおりです。
class SumRes r where
sumOf :: Integer -> r
instance SumRes Integer where
sumOf = id
instance (Integral a, SumRes r) => SumRes (a -> r) where
sumOf x = sumOf . (x +) . toInteger
しかし、問題は次のとおりです。関数が引数なしで呼び出されると、機能しません。
Couldn't match expected type 'Integer' with actual type 'Integer -> r0'
Probable cause: 'sumOf' is applied to too few arguments
たとえば、sumOf :: Integer
この関数を記述して、この関数を返してもらいたいと思い0
ます。
どうすればよいですか?
最も単純なバージョンはInteger
結果に対してのみ機能します。
これ0
は、追加のアイデンティティであるという事実を利用して、すでに書いたものをうまく処理します。
class SumRes r where
sumOf' :: Integer -> r
instance SumRes Integer where
sumOf' = toInteger
instance (Integral b, SumRes r) => SumRes (b -> r) where
sumOf' a b = sumOf' $! a + toInteger b
sumOf :: SumRes r => r
sumOf = sumOf' 0
2つのインスタンス、Integer
およびはb -> r
、本質的に重複しません。
より一般的な結果タイプを取得するには、多少異なるアプローチが必要です。これは、上記の2つのインスタンスInteger
がタイプ変数に置き換えられると、一緒にマッシュアップするためです。あなたがこれを行うことができますMultiParamTypeClasses
し、TypeFamilies
。
{-# LANGUAGE ScopedTypeVariables, AllowAmbiguousTypes, DataKinds,
KindSignatures, TypeApplications, MultiParamTypeClasses,
TypeFamilies, FlexibleInstances #-}
module SumRes2 where
data Nat = Z | S Nat
class SumRes (c :: Nat) r where
sumOf' :: Integer -> r
type family CountArgs a :: Nat where
CountArgs (_ -> r) = 'S (CountArgs r)
CountArgs _ = 'Z
instance Num r => SumRes 'Z r where
sumOf' = fromInteger
instance (Integral b, SumRes n r) => SumRes ('S n) (b -> r) where
sumOf' a b = sumOf' @n (a + toInteger b)
sumOf :: forall r n. (SumRes n r, CountArgs r ~ n) => r
sumOf = sumOf' @n 0
唯一の制限はIntegral
、関数型のインスタンスがある場合、それsumOf
を生成するために使用できないことです。しかし、それは実際には問題ではないはずです。私が使ってきたTypeApplications
し、AllowAmbiguousTypes
簡潔にするために、しかし、あなたは確かにプロキシ通過を使用したりすることができますTagged
代わりに。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加