Поливариадная функция Хаскеля без аргументов

Я пытаюсь создать поливариадную функцию в 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,

Как мне это сделать?

1 ответ

Решение

Самая простая версия работает только для 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

Два случая, Integer а также b -> rпо своей сути не перекрываются.

Труднее путь

Чтобы получить более общие типы результатов, вам нужен несколько иной подход, потому что два описанных выше примера вместе 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 вместо.

Другие вопросы по тегам