Следующий фрагмент кода заимствован из вики-страницы Haskell, чтобы носить с собой словарь классов типов вместе с экзистенциальным тип:

{-# language ExistentialQuantification #-}
module Experiment1 where

data Showable = forall x. Show x => Showable x
instance Show Showable where showsPrec p (Showable x) = showsPrec p x

resultStr :: String
resultStr = show (Showable ()) -- "()"

Можно ли написать функцию f :: (forall x. x -> result) -> result, которая может принимать конструктор Showable (или любой другой конструктор данных к экзистенциальному типу) в качестве аргумента?

Одна неудачная попытка сделать это выглядит так:

{-# language ExistentialQuantification, RankNTypes, ConstraintKinds #-}

module Experiment2 where

-- import Data.Constraint (Dict(..), withDict)

data Showable = forall x. Show x => Showable x
instance Show Showable where showsPrec p (Showable x) = showsPrec p x

f :: (cxt (), cxt result) => (forall x. cxt x => x -> result) -> result
f mkResult = mkResult ()

resultStr :: String
resultStr = show (f Showable)

Как следует из моего прокомментированного импорта выше, у меня сложилось впечатление, что пакет constraints может позволить мне передать необходимые доказательства, но я не понимаю, как это сработает?

1
Rehno Lindeque 3 Янв 2018 в 04:58

2 ответа

Лучший ответ

Ваша неудачная попытка сработает, если вы предоставите способ определить cxt

import Data.Proxy

f :: (cxt (), cxt result) => p cxt -> (forall x. cxt x => x -> result) -> result
f _ mkResult = mkResult ()

resultStr :: String
resultStr = show (f (Proxy :: Proxy Show) Showable)
1
Cirdec 3 Янв 2018 в 03:43

Прошу прощения за публикацию собственного ответа, но я нашел еще одну альтернативу:

{-# language ExistentialQuantification, RankNTypes, ConstraintKinds, KindSignatures, TypeFamilies, FlexibleInstances #-}

module Experiment3 where

import GHC.Exts

data Showable (cxt :: * -> Constraint) = forall x. (cxt ~ Show, cxt x) => Showable x
instance Show (Showable Show) where showsPrec p (Showable x) = showsPrec p x

f :: cxt () => (forall x. cxt x => x -> result cxt) -> result cxt
f mkResult = mkResult ()

resultStr :: String
resultStr = show (f Showable :: Showable Show)

К сожалению, для этого требуется явная сигнатура типа в show (f Showable), в то время как моей целью было получить вывод типа (или, скорее, какой-то вид ограничения) через Showable. Так что этот ответ - не решение как таковое, а скорее еще один контрпример тому, что я хотел.

Я приму ответ Cirdec, поскольку он привел меня к такому выводу.

0
Rehno Lindeque 3 Янв 2018 в 05:42