И да и нет!
Прежде всего, ваш тип неточен в подписи функции. Взяв ваш пример wrapper 4 'a'
, возвращаемый тип функции — m (m (m (m a)))
(где m
— это []
), а не m a
.
Во-вторых, нам не разрешены бесконечные типы в системе типов Haskell, поэтому мы не сможем записать правильный тип, даже если захотим!
Тем не менее, мы можем решить обе эти проблемы с помощью некоторых новых типов, которые будут выполнять за нас рекурсию на уровне типов. Во-первых, Fix
:
newtype Fix f a = Fix { unFix :: f (Fix f a) }
Используя это, мы можем обертывать бесконечно:
wrap :: Monad m => Fix m a
wrap = Fix $ return $ wrap
Как видите, нам не нужен базовый элемент (в вашем примере a
), потому что мы никогда не попадем в базу рекурсии.
Но это не то, что вы хотели! «Бесконечность» здесь на самом деле является чем-то вроде отвлекающего маневра: вы хотите иметь возможность оборачивать что-то конечное число раз, используя аргумент, определяющий уровень обтекания.
Вы можете сделать что-то подобное этому с другой оболочкой:
data Wrap f a = Pure a | Wrap (f (Wrap f a))
wrapper :: Monad f => Int -> a -> Wrap f a
wrapper 0 x = Pure x
wrapper n x = Wrap $ pure $ wrapper (n-1) x
(На самом деле это свободная монада, которую мы здесь используем)
То, что вы ищете, именно, хотя (т. е. без оберток) можно сделать, однако это довольно сложно и, вероятно, не то, что вы ищете. Тем не менее, я включу его для полноты.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
import Data.Kind
import GHC.TypeLits
data N = Z | S N
type family Wrap (n :: N) (f :: Type -> Type) (a :: Type) :: Type where
Wrap Z f a = a
Wrap (S n) f a = Wrap n f (f a)
type family FromNat (n :: Nat) :: N where
FromNat 0 = Z
FromNat n = S (FromNat (n - 1))
data Ny (n :: N) where
Zy :: Ny Z
Sy :: Ny n -> Ny (S n)
class KnownN n where sing :: Ny n
instance KnownN Z where sing = Zy
instance KnownN n => KnownN (S n) where sing = Sy sing
wrap :: forall n f a. (KnownN (FromNat n), Monad f) => a -> Wrap (FromNat n) f a
wrap = go @(FromNat n) @f @a sing
where
go :: forall n f a. Monad f => Ny n -> a -> Wrap n f a
go Zy x = x
go (Sy n) x = go @_ @f n (return @f x)
main = print (wrap @4 'a' == [[[['a']]]])
person
oisdk
schedule
15.08.2019
foo = () : foo
. Связанный вопрос: stackoverflow.com/questions/9566683 / - person AJF   schedule 16.08.2019