たとえば、19ページ。関数適用は、tail call (すなわち jump)とありますね。
fromIntegral :: (Num a, Integral i) => i -> a
(Floating a, Bounded i) の場合だけ、ノーマライズする処理を入れたいです。class FromIntegralNormalized i a where fromIntegralNormalized :: i -> a instance (Integral i, Num a, Bounded i, Floating a) => FromIntegralNormalized i a where fromIntegralNormalized = (/ fromIntegral (maxBound :: i)) . fromIntegral instance (Integral i, Num a) => FromIntegralNormalized i a where fromIntegralNormalized = fromIntegral
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
data WhetherNormalize i a where
BoundedNormalize :: (Bounded i, Floating a) => i -> WhetherNormalize i a
WithoutNormalize :: i -> WhetherNormalize i a
fromIntegralWithNormalize :: forall i a. (Integral i, Num a) => WhetherNormalize i a -> a
fromIntegralWithNormalize (BoundedNormalize x) = fromIntegral x / fromIntegral (maxBound :: i)
fromIntegralWithNormalize (WithoutNormalize x) = fromIntegral x
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables #-}
import
class FromIntegralNormalized i a where
fromIntegralNormalized :: i -> a
boundedToFloating :: forall i a. (Integral i, Bounded i, Num a, Floating a) => i -> a
boundedToFloating = (/ fromIntegral (maxBound :: i)) . fromIntegral
instance {-# OVERLAPS #-} (Integral i, Bounded i) => FromIntegralNormalized i Float where
fromIntegralNormalized = boundedToFloating
instance {-# OVERLAPS #-} (Integral i, Bounded i) => FromIntegralNormalized i Double where
fromIntegralNormalized = boundedToFloating
instance (Integral i, Num a) => FromIntegralNormalized i a where
fromIntegralNormalized = fromIntegral
main = do
print (fromIntegralNormalized (64 :: Int8) :: Int)
print (fromIntegralNormalized (64 :: Int8) :: Float)
print (fromIntegralNormalized (64 :: Int8) :: Double)
OVERLAPS の方法だと、呼び出し元に (Num a) の制約しかなかったら、ノーマライズしてくれないですね。hoge :: (Num a) => a hoge = fromIntegralNormalized (100 :: Word8) >>> hoge :: Int 100 >>> hoge :: Float 100.0
data Normalizing i a where NonNormalized :: Normalizing i a Normalized :: (Bounded i, Fractional a) => Normalizing i a fromIntegral' :: forall i a. (Integral i, Num a) => Normalizing i a -> i -> a fromIntegral' NonNormalized = fromIntegral fromIntegral' Normalized = (/ fromIntegral (maxBound :: i)) . fromIntegral
constraints-emerge のプラグインも試してみましたが、呼び出し元に Emerge 制約が伝播していくのが気になるので見送りました。type Key = String type Value = String data Hoge = [(Key, Value)]
data Member = Name String | Arguments [Argument] data Field a = Field a [Member]
Field a (例えば Field Int )をとって Int か、他の型に包んだ Some Int のような型を生成できるのでしょうか。 Generics とか使えばできるのかなとは考えてみたのですが上手くまとまらないです。(完全にGraphQLのAST作ってそこから型作る話です)Key があるのかコンパイル時にすべて求められるのであれば、可能です。Foo Int から Int や Some Int を生成するというのがよくわからないです。data Nyaan a = Nyaan a
a の型を Field a の型と一致させるような仕組みが作れないかなということですDerive client implementations from typesと計画しているように型からクエリーを組み立てる関数を生成するっていうアプローチではない?
travis がメモリ不足で死ぬ時は -j 1 オプションで回避したことがありますが、ちょっと違う感じですか?Couldn’t repro on stackage nightly (GHC 8.4).
ghc-8.4 系の lts-12.0 でもやっぱりダメな感じですか?Data.Extensible のレコードから Web.Internal.FormUrlEncoded の Form に変換する以下のようなコードで
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Hrafnar.Service.Common
( AwaitRequest
, Server
) where
import Data.Extensible
import Data.HashMap.Strict as HM
import GHC.TypeLits
import Web.Internal.FormUrlEncoded
instance Forall (KeyValue KnownSymbol (Instance1 ToFormKey h)) xs => ToForm (Field h :* xs) where
toForm = Form . hfoldlWithIndexFor
(Proxy :: Proxy (KeyValue KnownSymbol (Instance1 ToFormKey h)))
(\k m v -> HM.insert (toFormKey $ symbolVal $ proxyAssocKey k) [toFormKey v] m)
HM.empty
• Could not deduce (ToFormKey (Field h x))
arising from a use of ‘toFormKey’
from the context: Forall
(KeyValue KnownSymbol (Instance1 ToFormKey h)) xs
bound by the instance declaration
at src/Hrafnar/Service/Common.hs:33:10-91
or from: KeyValue KnownSymbol (Instance1 ToFormKey h) x
bound by a type expected by the context:
KeyValue KnownSymbol (Instance1 ToFormKey h) x =>
Membership xs x
-> HashMap Text [Text] -> Field h x -> HashMap Text [Text]
at src/Hrafnar/Service/Common.hs:(34,19)-(37,12)
• In the expression: toFormKey v
In the second argument of ‘HM.insert’, namely ‘[toFormKey v]’
In the expression:
HM.insert (toFormKey $ symbolVal $ proxyAssocKey k) [toFormKey v] m
Field h kv のインスタンスも必要なので、 instance ToFormKey (h (AssocValue kv)) => ToFormKey (Field h kv) も定義すると通ると思いますinstance ToFormKey (h (AssocValue kv)) => ToFormKey (Field h kv) where ToFormKey = undefined
Record を作り toForm してみたのですが
• No instance for (ToFormKey (Identity Text))
arising from a use of ‘toForm’
extensible のソース見ながらderiving instance ToFormKey (h (AssocValue kv)) => ToFormKey (Field h kv)
• Can't make a derived instance of ‘ToFormKey (Field h kv)’:
‘ToFormKey’ is not a standard derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
instance ToForm HogeType とやってみたけどダメでした