this article on writing polyvariadic functions in Haskell을 읽은 후, 나는 내 자신의 것을 쓰려고 시도했다.하스켈의 다변량 함수
처음에는 일반화하려고 시도 했으므로 주어진 인수를 축소하여 가변 함수를 반환하는 함수를 가질 수있었습니다. 그러나
{-# OPTIONS -fglasgow-exts #-}
module Collapse where
class Collapse a r | r -> a where
collapse :: (a -> a -> a) -> a -> r
instance Collapse a a where
collapse _ = id
instance (Collapse a r) => Collapse a (a -> r) where
collapse f a a' = collapse f (f a a')
, 컴파일러가 마음에 들지 않았다
Collapse.hs:5:9:
Functional dependencies conflict between instance declarations:
instance Collapse a a -- Defined at Collapse.hs:5:9-20
instance (Collapse a r) => Collapse a (a -> r)
-- Defined at Collapse.hs:7:9-43
내가 다시 가서 최종 결과에 대한 래퍼 형식을 추가 한 경우, 그러나, 일 :
module Collapse where
class Collapse a r | r -> a where
collapse :: (a -> a -> a) -> a -> r
data C a = C a
instance Collapse a (C a) where
collapse _ = C . id
instance (Collapse a r) => Collapse a (a -> r) where
collapse f a a' = collapse f (f a a')
sum :: (Num a, Collapse a r) => a -> r
sum = collapse (+)
이 변경 작업을 마치면 컴파일 된 것이므로 ghci
에 collapse
함수를 사용할 수 있습니다.
ghci> let C s = Collapse.sum 1 2 3 in s
6
최종 결과에 래퍼 유형이 필요한 이유가 확실하지 않습니다. 누구든지 그것을 설명 할 수 있다면, 나는 그것을 높이 평가할 것이다. 필자는 컴파일러가 함수 종속성에 문제가 있음을 알았지 만 아직 펀드를 제대로 사용하지는 못했습니다.
나중에 다른 태도를 취하고 목록을 취하여 값을 반환하는 함수에 대해 가변 인수 생성기를 정의하려고했습니다. 나는 같은 컨테이너 속임수를 써야했고 또한 UndecidableInstances
을 허용해야했다. 내 생각
ghci> let V l = Variadic.list 1 2 3 in l
[1,2,3]
ghci> let vall p = Variadic.foldl (\b a -> b && (p a)) True
ghci> :t vall
vall :: (Variadic b Bool r) => (b -> Bool) -> r
ghci> let V b = vall (>0) 1 2 3 in b
True
: 그것은 컴파일하면
Variadic.hs:7:0:
Illegal instance declaration for `Variadic a b (V b)'
(the Coverage Condition fails for one of the functional dependencies;
Use -XUndecidableInstances to permit this)
In the instance declaration for `Variadic a b (V b)'
Variadic.hs:9:0:
Illegal instance declaration for `Variadic a b (a -> r)'
(the Coverage Condition fails for one of the functional dependencies;
Use -XUndecidableInstances to permit this)
In the instance declaration for `Variadic a b (a -> r)'
그러나, 나는 성공적으로 ghci에서 그것을 사용할 수 있습니다
{-# OPTIONS -fglasgow-exts #-}
{-# LANGUAGE UndecidableInstances #-}
module Variadic where
class Variadic a b r | r -> a, r -> b where
variadic :: ([a] -> b) -> r
data V a = V a
instance Variadic a b (V b) where
variadic f = V $ f []
instance (Variadic a b r) => Variadic a b (a -> r) where
variadic f a = variadic (f . (a:))
list :: Variadic a [a] r => r
list = variadic . id
foldl :: (Variadic b a r) => (a -> b -> a) -> a -> r
foldl f a = variadic (Prelude.foldl f a)
UndecidableInstances
을 허용하지 않고 컴파일러는 내 인스턴스 선언은 불법이라고 불평 내가 찾고있는 이유는 왜 최종 값을위한 컨테이너 유형이 필요한지에 대한 설명뿐 아니라 모든 다양한 functio 최종 종속성이 필요합니다..
ghci> let vsum = Variadic.foldl (+) 0
<interactive>:1:10:
Ambiguous type variables `a', `r' in the constraint:
`Variadic a a r'
arising from a use of `Variadic.foldl' at <interactive>:1:10-29
Probable fix: add a type signature that fixes these type variable(s)
<interactive>:1:10:
Ambiguous type variable `a'in the constraint:
`Num a' arising from the literal `0' at <interactive>:1:29
Probable fix: add a type signature that fixes these type variable(s)
ghci> let vsum' = Variadic.foldl (+)
ghci> :t vsum'
(Num a, Variadic a a r) => t -> a -> r
ghci> :t vsum' 0
(Num a, Variadic a a r) => a -> r
ghci> let V s = vsum' 0 1 2 3 in s
6
내가 UndecidableInstances
을 허용에서 그 다툼 같은데요,하지만 나도 몰라, 내가 더 무슨 일이 일어나고 있는지 이해하고 싶습니다.
실험중인 멋진 코드입니다. 그리고 Oleg Kiselyov가 작성한 기사는 훌륭합니다. 처음 읽었을 때 완전히 저를 날려 버렸지 만 여전히 그 효과가 있습니다. :-) 래퍼 유형의 필요성에 대한 답변을 한 번 보았습니다 ... 도움이되기를 바랍니다. –