Skip to content

Instantly share code, notes, and snippets.

@tonymorris
Last active March 18, 2026 22:38
Show Gist options
  • Select an option

  • Save tonymorris/700328dad2130a67fb80d802a1063735 to your computer and use it in GitHub Desktop.

Select an option

Save tonymorris/700328dad2130a67fb80d802a1063735 to your computer and use it in GitHub Desktop.
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies #-}
-- If there were an opportunity to fix the IsList type-class...
import Control.Lens
import Data.List.NonEmpty hiding (fromList)
class FromList l f | l -> f where
type Item l
fromList :: [Item l] -> f l
-- |
-- >>> fromList [1,2,3] :: Identity [Int]
-- Identity [1,2,3]
-- >>> fromList [] :: Identity [Int]
-- Identity []
instance FromList [a] Identity where
type Item [a] = a
fromList = pure
-- |
-- >>> fromList [] :: Maybe (NonEmpty Int)
-- Nothing
-- >>> fromList [1] :: Maybe (NonEmpty Int)
-- Just (1 :| [])
-- >>> fromList [1,2,3] :: Maybe (NonEmpty Int)
-- Just (1 :| [2,3])
instance FromList (NonEmpty a) Maybe where
type Item (NonEmpty a) = a
fromList [] = Nothing
fromList (h:t) = Just (h :| t)
data MustBeTwo a =
IsZero | IsOne | IsMoreThanTwo | IsTwo a
deriving (Eq, Ord, Show, Functor)
-- |
-- >>> fromList [] :: MustBeTwo (Int, Int)
-- IsZero
-- >>> fromList [1] :: MustBeTwo (Int, Int)
-- IsOne
-- >>> fromList [1,2] :: MustBeTwo (Int, Int)
-- IsTwo (1,2)
-- >>> fromList [1,2,3] :: MustBeTwo (Int, Int)
-- IsMoreThanTwo
-- >>> fromList [1,2,3,4] :: MustBeTwo (Int, Int)
-- IsMoreThanTwo
instance FromList (a, a) MustBeTwo where
type Item (a, a) = a
fromList [] = IsZero
fromList [_] = IsOne
fromList [a1, a2] = IsTwo (a1, a2)
fromList (_:_:_:_) = IsMoreThanTwo
-- |
-- >>> fromList [] :: Maybe (Maybe Int)
-- Just Nothing
-- >>> fromList [1] :: Maybe (Maybe Int)
-- Just (Just 1)
-- >>> fromList [1,2] :: Maybe (Maybe Int)
-- Nothing
-- >>> fromList [1,2,3] :: Maybe (Maybe Int)
-- Nothing
instance FromList (Maybe a) Maybe where
type Item (Maybe a) = a
fromList [] = Just Nothing
fromList [a] = Just (Just a)
fromList (_:_:_) = Nothing
class FromList l f => IsList l f | l -> f where
isList :: Iso' (f l) [Item l]
fromList' :: IsList l f => [Item l] -> f l
fromList' = review isList
-- |
-- >>> view isList (Identity [1,2,3 :: Int])
-- [1,2,3]
-- >>> review isList [1,2,3] :: Identity [Int]
-- Identity [1,2,3]
instance IsList [a] Identity where
isList = iso runIdentity fromList
-- |
-- >>> view isList (Nothing :: Maybe (NonEmpty Int))
-- []
-- >>> view isList (Just (1 :| [2,3]))
-- [1,2,3]
-- >>> review isList [] :: Maybe (NonEmpty Int)
-- Nothing
-- >>> review isList [1,2,3] :: Maybe (NonEmpty Int)
-- Just (1 :| [2,3])
instance IsList (NonEmpty a) Maybe where
isList = iso (maybe [] (\(h:|t) -> h:t)) fromList
-- not possible
-- instance IsList (a, a) MustBeTwo where
-- not possible
-- instance IsList (Maybe a) Maybe where
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment